Consider following models:
# models.py
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=40)
number_of_publications = models.PositiveIntegerField(default=0)
def __str__(self):
return self.name
class Publication(models.Model):
name = models.CharField(max_length=80)
text = models.TextField()
tags = models.ManyToManyField(Tag, related_name="publications")
# urls.py
from .views import publications_tagged
from django.urls import path
urlpatterns = [
path('publications/tagged/<str:name>', publications_tagged)
]
# views.py
from .models import Tag, Publication
from django.shortcuts import get_object_or_404, render
def publications_tagged(request, name):
tag = get_object_or_404(Tag.objects.prefetch_related('publications'), name=name)
return render(request, 'myapp/tagged_questions.html', {'tag': tag})
Ok, so when we'd go to a template and make a for-loop that will create a representation of every publication and show appropriate tags of it, Django would make a database call for every publication to fetch all the tags the publication has, meaning:
Iteration x
of tag.tags_set
-> check what tags match with publication X
.
Of course, we can just not show tags and everything will work like magic (utilizing prefetch_related
), but that's not what we want :)
How could we do something similar in Django?
What we want is some kind of optimized way to achieve such a result, because stackoverflow renders 15 items really fast, which makes me think they do not do it the monkey way that Django does by default.
This is what html might look like
This is what html code might look like
P.S. My problem doesn't quite sound like that. But just in case anyone would say: "Oh, it's a bad design, you shouldn't do that at all" I decided to show an example.
CodePudding user response:
You can add a property to your Publication
model to render tags
as a list of strings, so:
class Publication(models.Model):
text = models.TextField()
tags = models.ManyToManyField(Tag)
@property
def tags_list(self):
# renders as ["django", "python", ...]
return list(self.tags.values_list("name", flat=True))
Make sure you use
prefetch_related("tags")
to optimize your query.
CodePudding user response:
The answer is really simple, all you have to do is in the prefetch_related
specify publications__tags
, which leaves you with
tag = get_object_or_404(Tag.objects.prefetch_related('publications', 'publications__tags'), name=name)