繁体   English   中英

如何纠正我的ORM语句以显示未与Django中的用户关联的所有朋友?

[英]How can I correct my ORM statement to show all friends not associated with a user in Django?

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

如何返回所有与first_name ='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)-请注意,我理解控制器应该是皮包骨头的,但仍在学习道歉。 我在下面的代码段中尝试过(在多次尝试使用更干净的方法失败之后)是尝试并首先抓住丹尼尔斯的朋友(将它们填充到列表中,然后删除所有重复的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>

我想类似的事情会做。 然后,将users列表,并获得这些用户的名字和姓氏。

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

这里注意,而Friendships.friend是一个foreignkey类型的Users可以通过用户实例(即daniels列表)中friend__in排除这些用户。

试试这个,代替friend_of_daniel.friend.id,您应该从用户模型中排除结果。

像这样的东西:

    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)

谢谢。

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

因此,代替:

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)

与您的list()-set()强制转换(确保您的列表没有重复的元素)相同,并且flat_True的values_list可以自定义为相关“用户”表中的任何字段:.values_list(' friend__id',flat = True)或.values_list('friend__first_name',flat = True)以获得丹尼尔朋友的名字的列表。

回到您的一般问题,您可以使用您的related_names直接在一行中进行整个查询,因为我不确定您想要什么(一个用户实例,一个Friendship实例或仅一个姓氏和名字的列表)将为您提供许多选择:

  • 如果您想要一个Friendship实例(在示例代码中要尝试的操作):

     friendships_not_friends_with_daniel = Friendships.objects\\ .exclude(friend__first_name="Daniel") 

    这等效于@Rafael在其答案中提出的建议:

    daniels = Users.objects.filter(first_name =“ Daniel”)#可能有多个Daniel用户= Friendships.objects.exclude(friend__in = daniels)

    在这里,我通过用双下划线(在Django中是非常强大的标准)引用相关表中的字段将他的第一个查询嵌入到排除中。

  • 如果您想要一个用户实例:

     users_with_no_friendship_with_daniel = Users.objects\\ .exclude(usersfriend__friend__first_name="Daniel") 

    在这里,您使用模型的相关名称来从用户表访问友谊表,然后检查该用户的朋友是否称为Daniel。 这种查询方式理解起来有点复杂,但是一旦您习惯了它,它就会变得非常强大,因为它与口语非常相似:您希望所有用户,但不包括拥有朋友名字的,具有友谊的用户。是丹尼尔。 根据一个用户有多少个朋友或有多少个用户被称为Daniel,您可能会添加一些distinct()方法或将查询分为两个。

    作为建议,也许您可​​以改进模型中的相关名称,因为如果您有一个用户实例并希望获得相关的友谊,则使用该名称:user_instance.friendships而不是user_instance.usersfriend和user_instance.friendsfriendships而不是user_instance.friendsfriend ....不知道,我总是很难选择好的相关名称...

  • 如果要列出用户的名字和姓氏元组:

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

很抱歉,如果不清楚,请询问,我会尽力解释。 (我在stackoverflow中是一个新手)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM