Python 为什么值列表在Django中保留过滤器?

Python 为什么值列表在Django中保留过滤器?,python,django,django-queryset,python-3.5,Python,Django,Django Queryset,Python 3.5,鉴于以下模型类别: from django.db import models class User(models.Model): friends = models.ManyToManyField('self', symmetrical=False, blank=True) 如果我有一个由n个用户组成的查询集,其中至少有一个有两个朋友,并通过按朋友id筛选该查询集来检索该用户,然后对该查询集执行调用,如下所示: all_users = User.objects.all() single

鉴于以下模型类别:

from django.db import models

class User(models.Model):
    friends = models.ManyToManyField('self', symmetrical=False, blank=True)
如果我有一个由n个用户组成的查询集,其中至少有一个有两个朋友,并通过按朋友id筛选该查询集来检索该用户,然后对该查询集执行调用,如下所示:

all_users = User.objects.all()
single_user = User.objects.filter(friends=2)
single_user.values_list('friends', flat=True)
single_user.first().friends.values_list('id', flat=True)
结果如下所示:

>>> [2]
但如果我执行相同的.values\u list调用对象的friends字段本身,如下所示:

all_users = User.objects.all()
single_user = User.objects.filter(friends=2)
single_user.values_list('friends', flat=True)
single_user.first().friends.values_list('id', flat=True)
结果输出为:

>>> [2, 3]
如果这些调用是在同一个对象上进行的,为什么输出不同

作为参考,这是使用Django 1.10和Python 3.5.2实现的

编辑:我想澄清一些困惑。我的问题不是我误解了问题本身的结果。在这两种情况下,我最终得到了正确的用户对象。不同之处在于,在一种情况下,我得到了计数为1的查询集,而在另一种情况下,我得到了用户对象的实例

因此,以不同的方式陈述我的问题:我困惑的是,调用同一对象的不同表示上的值列表如何导致不同的输出

例如,我有以下查询集

<QuerySet [<User: John Doe, ID: 1]>

它们是不同的,因为两个查询的意思并不相同

sqlparse.format(str(user.first().friends.values_list('id', flat=True).query))
user.values\u list('friends',flat=True)
…返回用户的好友ID

user.first().friends.values\u list('id',flat=True)
…返回'user'的第一个朋友的id
。换句话说,您实际上是在这里查找不同用户的朋友


调试此类内容的一个好方法是查看查询生成的SQL。这可能有助于了解Django是如何翻译查询的

str(user.first().friends.values_list('id', flat=True).query)
vs

无法读取输出?使用sqlparse

sqlparse.format(str(user.first().friends.values_list('id', flat=True).query))

如果使用多个关系,则会得到一个新表来存储两个表之间的关系

yourapplabel\u用户\u朋友示例 User.objects.filter(friends=2) 单用户.objects.first()
用户。修正了错误。这是一个解释问题的例子。这个问题不是关于应该命名什么模型,而是关于查询集。谢谢你的输入。我选择单数是希望说明它是一个iterable of one。在我们的实际代码中,我们遵循您详细介绍的指导原则。编辑此问题主要是为了提高可读性。此问题最初是由以下查询引发的:
User.objects.filter(friends=2).values\u list('friends',flat=True)
。我觉得这一点很重要,因为它消除了很多关于他是如何得到不同结果的困惑。问题不在于“值”列表在同一对象上给出了两个不同的结果,而在于“值”列表直接与过滤器链接。标题中的问题与此事件有关,而不是显示的示例。user.first().friends.values_list()是否会返回用户查询集中第一个用户的朋友的ID列表?在我的例子中,两个版本都作用于一个实例:一个在QuerySet中,另一个作为用户实例。虽然QuerySet生成了两个完全不同的SQL查询,但我认为@david lam对它们的解释不太正确。区别似乎确实在于是对模型实例还是对中间查询集进行操作。@das-g知道为什么实例和查询集之间的结果不同吗?因为Django构建查询的方式(有些天真)。尽管来自QuerySet的查询结果是否是预期结果(或者更确切地说,是计算预期结果的查询,尽管结果并不明显),或者这是否是Django bug,并且查询结果实际上应该是相同的,但我不知道。谢谢您的回答。在我的情况下,单用户对象在ManyToManyField中有两个朋友。但是,当我在实例字段(在本例中为friends)上调用values_list时,以及在包含该实例的QuerySet上调用values_list时,它会给出两个不同的结果。如果我试图获取数据的领域是相同的,为什么它们的行为会不同?您的答案使用模型类的.objects。我正在使用已经过滤过的QuerySets。我希望这能澄清问题。对不起,我的评论太冗长了。我想先检查一下你是否完全理解我的答案。我以为您无法理解
单用户.objects.filter(friends=2).值列表('friends',flat=True)
单用户.objects.first().friends.values\u列表('id',flat=True)
之间的区别。我给了你们示例数据和示例返回,让你们理解。你们用“self”定义了manytomanyfield。您可以认为从用户id是用户,到用户id是朋友。它可能会混淆,因为它将自己称为“self”manytomanyfield定义。我完全理解两行上的查询和数据状态之间的差异。但是,如果您有一个对象实例:
user=user.objects.all().first()
和do
user.friends.values\u list('id',flat=True)
它将在M2M管理器返回的查询集上执行值列表。这将产生与
users=User.objects.filter(id=1)
相同的结果,然后执行
users.values\u list('friends',flat=True)
。据我所知,两者都在访问同一个字段和同一个表。好的。您理解
User.objects.filter(friends=something)
是不同的。现在,您将其更改为
User.objects.filter(id=1)
User.objects.first().friends.values\u list('id',flat=True)
User.objects.filter(id=1).values\u list('friends',flat=True)
应该返回相同的结果,我认为。您能否为
User.objects.filter(id=1)
共享返回信息
User.objects.first().friends.values\u list('id',flat=True)
User.objects.filter(id=1).va
User.objects.filter(friends=2)
# return : 1 instances because there are only one 2 in to_user_id column
User.objects.filter(friends=1)
# return : 3 instances
User.objects.filter(friends=3)
# return : 0 instances

single_user.filter(friends=2).values_list('friends', flat=True)
# return : [2]
single_user.filter(friends=2).values_list('id', flat=True)
# return : [1] 
#because id 1 User instance has friends which is id 2 as ManyToMany relationship

# this row
id | from_user_id | to_user_id |      
1    1              2
single_user.objects.first()     
# single_user.objects.first() return first instance in user table. id 1 instance

single_user.objects.first().friends.values_list('id', flat=True)
# return : [2,1]
# id 1 instance has 2 instances in ManytoMany relationship.
# so it returns [2,1]

single_user.objects.last().friends.values_list('id', flat=True)
# return : [1]
# single_user.objects.last() returns id 3
# because I have 1,2,3 instances in User table as example.
# if you see yourapplabel_user_friends table, 3 id instance have 1 id as friends.