Python 如何更正ORM语句以显示与Django中的用户没有关联的所有好友?

Python 如何更正ORM语句以显示与Django中的用户没有关联的所有好友?,python,django,orm,many-to-many,Python,Django,Orm,Many To Many,在我的Django应用程序中,我有两个模型,一个用户和一个友谊。两者之间存在多对多关系,因为用户可以有许多朋友,而朋友可以有许多其他用户朋友 如何返回与名为“Daniel”的用户不是朋友的所有朋友(名字和姓氏) Models.py: class Friendships(models.Model): user = models.ForeignKey('Users', models.DO_NOTHING, related_name="usersfriend") friend = mo

在我的Django应用程序中,我有两个模型,一个用户和一个友谊。两者之间存在多对多关系,因为用户可以有许多朋友,而朋友可以有许多其他用户朋友

如何返回与名为“Daniel”的用户不是朋友的所有朋友(名字和姓氏)

Models.py:

class Friendships(models.Model):
    user = models.ForeignKey('Users', models.DO_NOTHING, related_name="usersfriend")
    friend = models.ForeignKey('Users', models.DO_NOTHING, related_name ="friendsfriend")
    created_at = models.DateTimeField(blank=True, null=True)
    updated_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'friendships'


class Users(models.Model):
    first_name = models.CharField(max_length=45, blank=True, null=True)
    last_name = models.CharField(max_length=45, blank=True, null=True)
    created_at = models.DateTimeField(blank=True, null=True)
    updated_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'users'
到目前为止,以下是我在控制器(views.py)中尝试的内容——请注意,我理解控制器应该很瘦,但仍在学习,所以道歉。我在下面的代码片段中尝试了(在多次尝试使用更干净的方法失败后)首先尝试抓取daniels的朋友(将他们填充到列表中,然后删除任何重复的id),然后根据他们的id过滤掉他们

# show first and last name of all friends who daniel is not friends with:

def index(req):

    friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
    daniels_friends = []
    for friend_of_daniel in friends_of_daniel:
        daniels_friends.append(friend_of_daniel.friend.id)

    daniels_friends = list(set(daniels_friends))

    not_daniels_friends = Friendships.objects.exclude(id__in=daniels_friends)

    context = {
        'not_daniels_friends':not_daniels_friends,
    }

return render(req, "friendapp/index.html",context)
然而,当我在我的视图(模板)文件中尝试以下内容时,我仍然会看到Daniels的朋友。知道我做错了什么吗

<ul>
    {% for not_daniel_friend in not_daniels_friends %}
        <li>{{ not_daniel_friend.user.first_name }} {{ not_daniel_friend.user.last_name }}</li>
    {% endfor %}
</ul>
    {在not_daniels_friends%中为not_daniels_friends%}
  • {{{not_daniel_friend.user.first_name}{{{not_daniel_friend.user.last_name}}
  • {%endfor%}

试试这个,你应该把结果从用户模型中排除出来,而不是在_daniel.friend.id的friend_中

大概是这样的:

    def index(req):

        friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
        daniels_friends = []
        for friend_of_daniel in friends_of_daniel:
            daniels_friends.append(friend_of_daniel.friend.id)

        daniels_friends = list(set(daniels_friends))

        not_daniels_friends = Users.objects.exclude(id__in=daniels_friends)

        context = {
            'not_daniels_friends':not_daniels_friends,
        }

    return render(req, "friendapp/index.html",context)

谢谢。

试试这个,在_daniel.friend.id的friend_处,您应该将结果从用户模型中排除

大概是这样的:

    def index(req):

        friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
        daniels_friends = []
        for friend_of_daniel in friends_of_daniel:
            daniels_friends.append(friend_of_daniel.friend.id)

        daniels_friends = list(set(daniels_friends))

        not_daniels_friends = Users.objects.exclude(id__in=daniels_friends)

        context = {
            'not_daniels_friends':not_daniels_friends,
        }

    return render(req, "friendapp/index.html",context)

谢谢。

我想这样就行了。然后获取列表
用户
,并获取这些用户的名字和姓氏

daniels = Users.objects.filter(first_name="Daniel") # There may be more than one Daniel
users = Friendships.objects.exclude(friend__in=daniels)

请注意,Friendships.friend是
用户类型的
外键
,您可以在
中的
friend\u中传递用户实例(即
daniels
列表),以排除这些用户。

我想这样做就可以了。然后获取列表
用户
,并获取这些用户的名字和姓氏

daniels = Users.objects.filter(first_name="Daniel") # There may be more than one Daniel
users = Friendships.objects.exclude(friend__in=daniels)

请注意,虽然Friendships.friend是
用户类型的
外键
,但您可以在
中传递用户实例(即
daniels
列表)以排除这些用户。

首先作为一般性注释:填充ID列表的更干净方法是使用(部分.values()方法(在Django的早期版本中)。它有一个“平面”标志,用于创建所需的列表

daniels = Users.objects.filter(first_name="Daniel") # There may be more than one Daniel
users = Friendships.objects.exclude(friend__in=daniels)
因此,不是:

friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
    daniels_friends = []
    for friend_of_daniel in friends_of_daniel:
        daniels_friends.append(friend_of_daniel.friend.id)

    daniels_friends = list(set(daniels_friends))
您可以在一行中执行以下操作:

daniels_friends = Friendships.objects \
       .filter(user__first_name='Daniel') \
       .distinct('friend') \
       .values_list('friend', flat=True)
distinct与list()-set()转换相同(它确保列表中没有重复的元素),可以对相关“用户”表中的任何字段自定义flat=True的值。\u list:.values\u list('friend\u id',flat=True)或.values\u list('friend\u first\u name',flat=True),以获取Daniel朋友的名字列表

回到您的一般问题,您可以使用相关的_名称直接在一行中完成整个查询,因为我不确定您想要什么(一个用户实例、一个友谊实例或只是一个名字和姓氏列表)。我将为您提供许多选项:

  • 如果您想要一个友谊实例(您在示例中尝试的内容 代码):

    这相当于@Rafael在回答中提出的:

    daniels=Users.objects.filter(first_name=“Daniel”)#可能有 不止一个Daniel用户= Friendships.objects.exclude(Friends\uu in=daniels)

    这里,我通过引用 相关表中的字段,带有双下划线(这是一个非常重要的 强大的Django标准)

  • 如果需要用户实例,请执行以下操作:

    users_with_no_friendship_with_daniel = Users.objects\
            .exclude(usersfriend__friend__first_name="Daniel")
    
    在这里,您使用模型的相关名称从 users表添加到friendships表,然后检查此用户的朋友是否叫Daniel。这种查询方式理解起来有点复杂,但一旦你习惯了,它就会变得非常强大,因为它与口语非常相似:你需要所有用户,但不包括那些有朋友的用户,他们的朋友的名字是丹尼尔。根据一个用户有多少朋友或有多少用户被称为Daniel,您可能需要添加一些不同的()方法或将查询一分为二

    作为建议,您可以改进模型中的相关名称,因为如果您有一个用户实例,并且希望获得相关的友谊,您将使用该名称:user\u instance.friends而不是user\u instance.usersfriend和user\u instance.friendships而不是user\u instance.friends。。。。不知道,我总是很难选择好相关的名字

  • 如果需要用户名和姓氏的元组列表:

    names_of_users_with_no_friendship_with_daniel = Users.objects\
            .exclude(usersfriend__friend__first_name="Daniel")\
            .values_list('first_name', 'last_name')
    

很抱歉,如果有什么不清楚的地方,请询问,我会尽量解释得更好。(我对stackoverflow很陌生)

首先作为一般性评论:填充ID列表的一种更干净的方法是使用(Django早期版本中.values()方法的一部分)。它有一个“平面”标志,用于创建所需的列表

因此,不是:

friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
    daniels_friends = []
    for friend_of_daniel in friends_of_daniel:
        daniels_friends.append(friend_of_daniel.friend.id)

    daniels_friends = list(set(daniels_friends))
您可以在一行中执行以下操作:

daniels_friends = Friendships.objects \
       .filter(user__first_name='Daniel') \
       .distinct('friend') \
       .values_list('friend', flat=True)
distinct与list()-set()转换相同(它确保列表中没有重复的元素),可以对相关“用户”表中的任何字段自定义flat=True的值。\u list:.values\u list('friend\u id',flat=True)或.values\u list('friend\u first\u name',flat=True),以获取Daniel朋友的名字列表

回到您的一般问题,您可以使用相关的_名称直接在一行中完成整个查询,因为我不确定您想要什么(一个用户实例、一个友谊实例或只是一个名字和姓氏列表)。我将为您提供许多选项:

  • 如果您想要一个友谊实例(您在示例中尝试的内容 代码):

    这相当于@Rafael在回答中提出的:

    daniels=Users.objects.filter(first_name=“Daniel”)#可能有 不止一个Daniel用户= Friendships.objects.exclude(Friends\uuuu in=daniels