对于我的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?
答案 0 :(得分: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()
查看:
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 %}
答案 1 :(得分:4)
除S.Lott的建议外,您可以考虑使用select_related()来限制数据库查询的数量;否则你的模板将对每个事件的循环进行查询。
Event.objects.all().select_related(depth=1)
深度参数不是必需的,但如果您的其他模型有其他外键,则会限制连接数。
答案 2 :(得分:1)
为了充分利用Django,你必须避免尝试加入。
“左外连接”实际上是具有可选关系的对象列表。
它只是一个事件列表,Event.objects.all()
。有些Event对象有评级,有些则没有。
您可以在视图中获得事件列表。您可以处理模板中的可选关系。
{% for e in event_list %}
{{ e }}
{% if e.rating_set.all %}{{ e.rating_set }}{% endif %}
{% endfor %}
是一个起点。
答案 3 :(得分:0)
我认为你必须做这样的事情。
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})
答案 4 :(得分:0)
最佳做法是
from django.db.models import Prefetch
event_list = Event.objects.all().prefetch_related(Prefetch(<related_name>, queryset=Rating.objects.filter(<criteria>)))
class Rating(models.Model):
event = models.ForeignKey(Event, related_name='ratings')
这将返回事件和这些事件对象的过滤评级