繁体   English   中英

Django - 过滤相关对象

[英]Django - filtering on related objects

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

如果我做:

event_list = Event.objects.filter(rating__user=request.user.id)

(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

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

filter方法是根据指定的条件过滤返回哪些对象,所以这里不是你想要的。 一种选择是执行第二次查询以检索当前User给定Event对象的所有评级。

楷模:

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()

看法:

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],
}

模板:

{% for event, user_rating in events %}
  {% if user_rating %} ... {% endif %}
{% endfor %}

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

Event.objects.all().select_related(depth=1)

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

为了充分利用 Django,您必须避免尝试进行连接。

“左外连接”实际上是具有可选关系的对象列表。

它只是一个事件列表Event.objects.all() 有些 Event 对象有一个评级,有些则没有。

您可以在视图中获得事件列表。 您可以处理模板中的可选关系。

{% for e in event_list %}
    {{ e }}
    {% if e.rating_set.all %}{{ e.rating_set }}{% endif %}
{% endfor %}

是一个起点。

最好的做法是

from django.db.models import Prefetch


event_list = Event.objects.all().prefetch_related(Prefetch(<related_name>, queryset=Rating.objects.filter(<criteria>)))

<related_name> = '评级' 如果:

class Rating(models.Model):
    event = models.ForeignKey(Event, related_name='ratings')

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

我认为你必须做这样的事情。

events=Event.objects.filter(rating__user=request.user.id)
ratings='(select rating from ratings where user_id=%d and event_id=event_events.id '%request.user.id
events=events.extra(select={'rating':ratings})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM