Django - 过滤相关对象

Tim*_*ham 18 django filter

对于我的Django应用程序,我有事件,评级和用户.评级通过外键与事件和用户相关.当显示事件列表时,我想通过user_id过滤事件的评级,因此我知道用户是否对事件进行了评级.

如果我做:

event_list = Event.objects.filter(rating__user=request.user.id)
Run Code Online (Sandbox Code Playgroud)

(request.user.id给出当前登录用户的user_id)...然后我只获取用户评分的事件而不是整个事件列表.

我需要的东西可以通过自定义SQL生成:

SELECT *
FROM `events_event`
LEFT OUTER JOIN (
  SELECT *
  FROM `events_rating`
  WHERE user_id = ##
  ) AS temp 
ON events_event.id = temp.user_id
Run Code Online (Sandbox Code Playgroud)

有没有更简单的方法,所以我不必使用自定义SQL?

Jon*_*nan 16

filter方法用于过滤基于指定条件返回的对象,因此这不是您想要的.一种选择是进行第二次查询以检索Event当前给定对象的所有评级User.

楷模:

import collections

from django.db import models

class RatingManager(models.Manager):
    def get_for_user(self, events, user):
        ratings = self.filter(event__in=[event.id for event in events],
                              user=user)
        rating_dict = collections.defaultdict(lambda: None)
        for rating in ratings:
            rating_dict[rating.event_id] = rating
        return rating_dict

class Rating(models.Model):
    # ...
    objects = RatingManager()
Run Code Online (Sandbox Code Playgroud)

视图:

events = Event.objects.all()
user_ratings = Rating.objects.get_for_user(events, request.user)
context = {
    'events': [(event, user_ratings[event.id]) for event in events],
}
Run Code Online (Sandbox Code Playgroud)

模板:

{% for event, user_rating in events %}
  {% if user_rating %} ... {% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)


小智 6

最好的做法是

from django.db.models import Prefetch


event_list = Event.objects.all().prefetch_related(Prefetch(<related_name>, queryset=Rating.objects.filter(<criteria>)))
Run Code Online (Sandbox Code Playgroud)

<相关名称> = '评级' 如果:

class Rating(models.Model):
    event = models.ForeignKey(Event, related_name='ratings')
Run Code Online (Sandbox Code Playgroud)

这将返回事件和这些事件对象的过滤评级


Dan*_*aab 5

除了S.Lott的建议,你可以考虑使用select_related()来限制数据库查询次数;否则您的模板将对每个事件通过循环进行查询。

Event.objects.all().select_related(depth=1)
Run Code Online (Sandbox Code Playgroud)

深度参数不是必需的,但如果您的其他模型有额外的外键,它将限制连接的数量。