从 Django 中的特定模型获取子一对多关系

Get sub One To Many relation from specific model in django

我有两个模型 UserSale,每个销售都有一个买家和一个卖家。我想从特定用户 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

提前谢谢大家

您可以像这样访问特定用户的销售和购买:

q = my_user.sale_set.all()

q = my_user.sale_set.filter(your fileter)

然后您可以使用以下方式访问买家或卖家:

buyer = q.buyer 

seller = q.seller

但请注意使用 q.last(),因为您无法访问查询集列表中的买家或卖家。

我希望这对您有所帮助。

你可以使用django values_list

https://docs.djangoproject.com/en/dev/ref/models/querysets/#values-list

所以,你可以使用下面的代码

buyer_list = my_user.sales.values_list('buyer', flat=True)

另外,如果你想删除重复值,Find distinct选项。

https://docs.djangoproject.com/en/4.0/ref/models/querysets/#distinct

有人称赞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' 方法。但它必须写入您要使用的所有用户列。

你的方案和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 确保您拥有所有买家数据,并且不会在每次 每次 销售时发送一个查询,更多 here) :

buyers = {sale.buyer for sale in my_user.sales.select_related('buyer')}

从多个用户获取

当您没有单个用户,而是多个用户时,情况会更糟,我认为最终会出现这种情况。如果您想让用户出来以防止多次调用数据库,您必须在这里做更多的魔术。

受您原始查询的启发,将是一个非常简单的 2 行代码段:

user_ids = my_user_qs.values_list('id', flat=True)
buyers = User.objects.filter(purchases__seller__id__in=user_ids)

简单。


现在让我们假设您想要 re-use buyers = {sale.buyer... 作为用户的方法,我们称它为 user.get_buyers():

buyers = [user.get_buyers() for user in my_users]

这将 运行 每个用户对数据库进行 1 次查询,即使只有数百个用户,也可能会非常慢。

你如何优化它?

首先你必须定义一个 Prefetch - 它告诉 Django 在最初 运行 你的用户查询时下载额外的数据。

from django.db.models import Prefetch

sales_prefetch = Prefetch('sales', Sale.objects.select_related('buyer', 'seller')
# no query runs yet

Prefetch 表示 “在评估应用此预取的查询集时,同时获取 Sale 查询并将其附加到 'sales' 子字段。此外,当您在它上面,加入销售 table 与用户 table 在买家和卖家.

然后你必须确保当你 运行 得到你的查询 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

结论

总的来说,通过用户模型进行原始查询会更好。使用 Prefetch,您仍然 运行 冒着在用户上使用您没有 运行 prefetch/select_related 的相关字段的风险,并且您将为每个用户触发数据库查询最终列表中的单个项目。

我强烈建议阅读并理解 select_relatedprefetch_related,因为它们是 Django 正确执行 JOIN 的方式。

https://docs.djangoproject.com/en/4.0/ref/models/querysets/#select-related https://docs.djangoproject.com/en/4.0/ref/models/querysets/#prefetch-related