考虑到我有以下关系:
class House(Model):
name = ...
class User(Model):
"""The standard auth model"""
pass
class Alert(Model):
user = ForeignKey(User)
house = ForeignKey(House)
somevalue = IntegerField()
Meta:
unique_together = (('user', 'property'),)
在一个查询中,我想获取房屋清单,以及当前用户是否有任何警报。
在SQL中我会这样做:
SELECT *
FROM house h
LEFT JOIN alert a
ON h.id = a.house_id
WHERE a.user_id = ?
OR a.user_id IS NULL
我发现我可以使用prefetch_related
来实现这样的目标:
p = Prefetch('alert_set', queryset=Alert.objects.filter(user=self.request.user), to_attr='user_alert')
houses = House.objects.order_by('name').prefetch_related(p)
上面的示例有效,但houses.user_alert
是一个列表,而不是Alert
对象。我每个房子每个用户只有一个警报,那么获取此信息的最佳方式是什么?
select_related
似乎无法奏效。哦,当然我知道我可以在多个查询中管理这个问题,但我真的希望在一个问题中完成它,以及“Django方式”。
提前致谢!
答案 0 :(得分:0)
如果您从多查询方法开始,然后尝试对其进行优化,则解决方案会更清晰。要获得每个房屋的user_alerts
,您可以执行以下操作:
houses = House.objects.order_by('name')
for house in houses:
user_alerts = house.alert_set.filter(user=self.request.user)
user_alerts
查询集将导致查询集中每个房屋的额外查询。您可以使用prefetch_related
来避免这种情况。
alerts_queryset = Alert.objects.filter(user=self.request.user)
houses = House.objects.order_by('name').prefetch_related(
Prefetch('alert_set', queryset=alerts_queryset, to_attrs='user_alerts'),
)
for house in houses:
user_alerts = house.user_alerts
这将需要两个查询,一个用于房屋,一个用于警报。我认为您不需要在此处选择相关内容来获取用户,因为您已经可以访问self.request.user
的用户。如果您愿意,可以将select_related
添加到alerts_queryset
:
alerts_queryset = Alert.objects.filter(user=self.request.user).select_related('user')
在您的情况下,user_alerts
将是一个空列表或包含一个项目的列表,因为您的unique_together
约束。如果您无法处理列表,则可以遍历查询集一次,并设置house.user_alert
:
for house in houses:
house.user_alert = house.user_alerts[0] if house.user_alerts else None