我有两个模型User
和Sale
,每个销售有一个买家和一个卖家。我想从特定用户my_user
中获得所有买家(也包括用户)。
class User(models.Model):
name = models.CharField(max_length=250, default='', blank=True)
# more fields....
class Sale (models.Model):
buyer = models.ForeignKey(
User,
blank=False,
null=False,
related_name='purchases',
on_delete=models.CASCADE,
)
seller = models.ForeignKey(
User,
blank=False,
null=False,
related_name='sales',
on_delete=models.CASCADE,
)
# more fields....
User.objects.filter(purchases__seller = my_user)
但是我想知道是否有一种方法可以直接使用my_user
对象来做到这一点。像这样
my_user.sales.buyer
提前感谢各位
你的台词和seokmin的解决方案有很大的不同:
my_user.sales.values_list('buyer', flat=True) # returns a list of ids
User.objects.filter(purchases__seller=my_user) # returns a QuerySet
你可以做一个更难看的理解(select_related
确保你有所有的买家数据,不会发送一个查询每个销售,更多在这里):
buyers = {sale.buyer for sale in my_user.sales.select_related('buyer')}
从多个用户获取
更糟糕的情况是,当你不是只有一个用户,而是有多个用户时,我认为最终会出现这种情况。如果你想让Users出来,以防止调用DB太多次,你必须在这里做一些更神奇的事情。
受您原始查询的启发,将是一个非常简单的2行代码片段:
user_ids = my_user_qs.values_list('id', flat=True)
buyers = User.objects.filter(purchases__seller__id__in=user_ids)
容易。
现在假设你想重新使用buyers = {sale.buyer...
作为用户的方法,我们称之为user.get_buyers()
:
buyers = [user.get_buyers() for user in my_users]
这将为每个用户运行一个对DB的查询,并且即使只有数百个用户也可能非常慢。
如何优化?
首先你必须定义一个Prefetch——它告诉Django在最初为用户运行查询时下载额外的数据。
from django.db.models import Prefetch
sales_prefetch = Prefetch('sales', Sale.objects.select_related('buyer', 'seller')
# no query runs yet
预取说"当计算这个预取应用于的查询集时,同时获取Sale查询并将其附加到'sales'子字段。此外,当您处理它时,将销售表与买方和卖方">上的用户表连接起来。
那么你必须确保当你运行获取my_users
的查询时,你使用这个预取。
my_users = Users.objects.prefetch_related(sales_prefetch)
这允许你做以下事情:
buyers = [user.get_buyers() for user in my_users]
# sends a single query and returns a list of lists of User objects
# you still have to flatten the list of lists
结论
总的来说,通过User模型使用原始查询会更好。使用Prefetch,你仍然有使用用户的相关字段的风险,你没有运行Prefetch/select_related,你会为最终列表中的每个项目触发一个DB查询。
我强烈推荐阅读和理解select_related
和prefetch_related
,因为它们是Django正确执行join的方式。
https://docs.djangoproject.com/en/4.0/ref/models/querysets/select-relatedhttps://docs.djangoproject.com/en/4.0/ref/models/querysets/prefetch-related
您可以像这样访问特定用户的销售和购买:
q = my_user.sale_set.all()
或
q = my_user.sale_set.filter(your fileter)
则可以使用:
访问买方或卖方buyer = q.buyer
seller = q.seller
,但要注意使用q.last(),因为你不能访问查询集列表中的买方或卖方。
我希望这对你有帮助。
buyer_list = my_user.sales.values_list('buyer', flat=True)
有人推荐values_list选项只带来值而不是对象。谢谢你的推荐。
所以,我找到了select_related选项。
https://docs.djangoproject.com/en/4.0/ref/models/querysets/select-related
如果你想使用select_related,也许这个例子类似于django文档的工作
buyers = set()
for sale in my_user.sales.select_related('buyer').all():
buyers.add(sale.buyer)
另一个解决方案是使用'values'方法。但是它必须写你想要使用的所有用户列。
如何组合select_related()和value()?(2016)