我的模特是这样的:
class Personne(BaseModel):
# [skip] many fields then:
photos = models.ManyToManyField(Photo, blank=True,
through='PersonnePhoto',
symmetrical=False,
related_name='parent')
def photo_profil(self):
a = PersonnePhoto.objects.filter(
personne=self, photo_type=PersonnePhoto.PHOTO_PROFIL)
return a[0] if len(a) else None
# [skip] many fields then:
travels = models.ManyToManyField(
TagWithValue, blank=True,
through='PersonneTravel',
default=None, symmetrical=False,
related_name='personne_travel')
class PersonneRelation(BaseModel):
src = models.ForeignKey('Personne', related_name='src')
dst = models.ForeignKey('Personne', related_name='dst')
opposite = models.ForeignKey('PersonneRelation',
null=True, blank=True, default=None)
is_reverse = models.BooleanField(default=False)
我需要显示一个人的所有联系人,并为每个联系人显示他/她的所有旅行和他/她的照片。
以下是我的观点中的代码:
class IndexView(LoginRequiredMixin, generic.TemplateView):
template_name = 'my_home/contacts/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['contacts'] = Personne.objects.get(
user=self.request.user).relations.all()
return context
非常简单。
问题出在我的模板中。 my_home/contacts/index.html
为每位联系人提供contact_detail.html
:
{% for c in contacts %}
{% with c as contact %}
{% include 'includes/contact_detail.html' %}
{% endwith %}
{% endfor %}
在contact_detail.html
中,我调用photo_profil
,它会进行查询以获取联系人图片的值。
{{ contact.photo_profil }}
这意味着,如果用户有100个联系人,我会为所有联系人执行 一个查询,然后为每个联系人执行100个查询。如何优化这个?我对旅行有同样的问题,实际上,联系人的每个ManyToMany字段也存在同样的问题。
答案 0 :(得分:1)
看起来你需要一些prefetch_related
善良:
context['contacts'] = (Personne.objects
.get(user=self.request.user)
.relations
.all()
.prefetch_related('travels', 'photos'))
但请注意,它会获取所有联系人的照片,这是您不希望的。基本上你有两个选择。将一些毛茸茸的原始SQL添加到Prefetch
对象的queryset
参数中。或者(正如我在其中一个项目中所做的那样)指定一个单独的main_photo
字段用于存储用户的头像(单独的ForeignKey
到Photo
,我的意思是,不是完全独立的一个) 。是的,它显然是非规范化,但查询变得很多更简单。毕竟,您的用户可以设置主照片。