如何更正我的 ORM 语句以显示与 Django 中的用户无关的所有朋友?
How can I correct my ORM statement to show all friends not associated with a user in Django?
在我的 Django 应用程序中,我有两个模型,一个是用户,一个是友谊。两者之间存在多对多关系,因为用户可以有很多朋友,而朋友可以有很多其他用户朋友。
我如何 return 所有与 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) -- 请注意,我知道控制器应该很瘦,但仍在学习,所以很抱歉。我在下面的代码片段中尝试的(在多次尝试更清洁的方法失败之后)是尝试首先抓住 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>
试试这个,在 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)
谢谢。
我想这样的事情就可以了。然后获取列表 users
,并获取这些用户的名字和姓氏。
daniels = Users.objects.filter(first_name="Daniel") # There may be more than one Daniel
users = Friendships.objects.exclude(friend__in=daniels)
请注意,虽然 Friendships.friend 是 Users
类型的 foreignkey
,但您可以传递 friend__in
中的用户实例(即 daniels
列表)以排除那些用户。
首先作为一般性评论:填充 id 列表的一种更简洁的方法是使用 .value_list() method from django(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)
distinct 与您的 list() - set() 转换相同(它确保您的列表没有重复的元素)并且 values_list with flat=True 可以自定义到相关的任何字段"user" table: .values_list('friend__id', flat=True) 或 .values_list('friend__first_name', flat=True) 获取列表丹尼尔的 first_names 个朋友。
回到您的一般问题,您可以使用 related_names 直接在一行中完成整个查询,因为我不太确定您想要什么(用户实例、友谊实例或只是名字和姓氏列表)我会给你很多选择:
如果你想要一个 Friendship 实例(你在你的示例中尝试的
代码):
friendships_not_friends_with_daniel = Friendships.objects\
.exclude(friend__first_name="Daniel")
这等同于@Rafael 在他的回答中提出的建议:
daniels = Users.objects.filter(first_name="Daniel") # There may be
more than one Daniel users =
Friendships.objects.exclude(friend__in=daniels)
在这里,我通过引用将他的第一个查询嵌入到排除中
相关 table 字段中带有双下划线(这是一个非常
Django 中的强大标准)。
如果你想要一个用户实例:
users_with_no_friendship_with_daniel = Users.objects\
.exclude(usersfriend__friend__first_name="Daniel")
此处您使用模型的相关名称从
users table 到 friendships table,然后查看这个用户的好友是不是大牛。这种查询方式理解起来有点复杂,但一旦你习惯了它就会变得非常强大,因为它与口语非常相似:你想要所有用户,但不包括有朋友的人,他们朋友的名字是丹尼尔。根据一个用户有多少朋友帽子或有多少用户叫 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')
很抱歉,如果有什么不清楚的地方,请提问,我会尽力解释得更好。 (我是 Whosebug 的新手)
在我的 Django 应用程序中,我有两个模型,一个是用户,一个是友谊。两者之间存在多对多关系,因为用户可以有很多朋友,而朋友可以有很多其他用户朋友。
我如何 return 所有与 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) -- 请注意,我知道控制器应该很瘦,但仍在学习,所以很抱歉。我在下面的代码片段中尝试的(在多次尝试更清洁的方法失败之后)是尝试首先抓住 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>
试试这个,在 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)
谢谢。
我想这样的事情就可以了。然后获取列表 users
,并获取这些用户的名字和姓氏。
daniels = Users.objects.filter(first_name="Daniel") # There may be more than one Daniel
users = Friendships.objects.exclude(friend__in=daniels)
请注意,虽然 Friendships.friend 是 Users
类型的 foreignkey
,但您可以传递 friend__in
中的用户实例(即 daniels
列表)以排除那些用户。
首先作为一般性评论:填充 id 列表的一种更简洁的方法是使用 .value_list() method from django(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)
distinct 与您的 list() - set() 转换相同(它确保您的列表没有重复的元素)并且 values_list with flat=True 可以自定义到相关的任何字段"user" table: .values_list('friend__id', flat=True) 或 .values_list('friend__first_name', flat=True) 获取列表丹尼尔的 first_names 个朋友。
回到您的一般问题,您可以使用 related_names 直接在一行中完成整个查询,因为我不太确定您想要什么(用户实例、友谊实例或只是名字和姓氏列表)我会给你很多选择:
如果你想要一个 Friendship 实例(你在你的示例中尝试的 代码):
friendships_not_friends_with_daniel = Friendships.objects\ .exclude(friend__first_name="Daniel")
这等同于@Rafael 在他的回答中提出的建议:
daniels = Users.objects.filter(first_name="Daniel") # There may be more than one Daniel users = Friendships.objects.exclude(friend__in=daniels)
在这里,我通过引用将他的第一个查询嵌入到排除中 相关 table 字段中带有双下划线(这是一个非常 Django 中的强大标准)。
如果你想要一个用户实例:
users_with_no_friendship_with_daniel = Users.objects\ .exclude(usersfriend__friend__first_name="Daniel")
此处您使用模型的相关名称从 users table 到 friendships table,然后查看这个用户的好友是不是大牛。这种查询方式理解起来有点复杂,但一旦你习惯了它就会变得非常强大,因为它与口语非常相似:你想要所有用户,但不包括有朋友的人,他们朋友的名字是丹尼尔。根据一个用户有多少朋友帽子或有多少用户叫 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')
很抱歉,如果有什么不清楚的地方,请提问,我会尽力解释得更好。 (我是 Whosebug 的新手)