Django queryset附加或注释相关对象字段 [英] Django queryset attach or annotate related object field

查看:88
本文介绍了Django queryset附加或注释相关对象字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

需要附加到与查询集结果相关的对象字段。

It is needed to attach to queryset results related object field.

模型:

class User(models.Model):
    name = models.CharField(max_length=50)
    friends = models.ManyToManyField('self', through='Membership',
        blank=True, null=True, symmetrical=False)


class Membership(models.Model):
    status = models.CharField(choices=SOME_CHOICES, max_length=50)
    from_user = models.ForeignKey(User, related_name="member_from")
    to_user = models.ForeignKey(User, related_name="member_to")

我可以这样做:

>>> User.objects.all().values('name', 'member_from__status')
[{'member_from__status': u'accepted', 'name': 'Ann'}, {'member_from__status': u'thinking', 'name': 'John'}]

'member_from__status'包含我需要的信息。但是与此同时,我还需要一个模型实例。

'member_from__status' contains information, that i need. But together with it, i need a model instance also.

我想要的是:

>>> users_with_status = User.objects.all().do_something('member_from__status')
>>> users_with_status
[<User 1>, <User 2>]

>>> users_with_status[0] # <-- this is an object, so i can access to all its methods

查询集中的每个实例都有一个具有相应值的'member_from__status'字段:

Every instance in queryset has a 'member_from__status' field with corresponding value:

>>> users_with_status[0].member_from__status
u'accepted'

如何实现?

推荐答案

您可以使用 注释 F

You can use annotate and F

>>> from django.db.models import F
>>> users = User.objects.all().annotate(member_from__status=F('member_from__status'))
>>> users[0].member_from__status
'accepted'

使用Django 1.11和2.2版本进行了测试

Tested with Django versions 1.11 and 2.2

在这里,我想我们对 member_to__status 比 member_from__status (我们希望用户被要求接受友谊,而不是相反)

Here I guess we are rather interested by member_to__status than member_from__status (we want the user being requested to accept the friendship, not the other way around)

以下是我的内容成员身份表:

status   |  from|   to
---------+------+-----
accepted |     1|    2
accepted |     2|    3
 refused |     3|    1

由于" 不可能有一个对称的,递归的 ManyToManyField (例如,用户1接受了用户2,因此用户1现在在用户2的朋友列表中,但用户2也在用户1的朋友中),这就是我将检索所有实际朋友的方式:

Since "it's not possible to have a symmetrical, recursive ManyToManyField" (e.g. user 1 accepted user 2 so user 1 is now in user 2's friend list but user 2 is also in user 1's friends), this is how I would retrieve all actual friends:

>>> for user in User.objects.all():
...     friends = user.friends.filter(member_to__status='accepted')
...     print(str(user.id) + ': ' + ','.join([str(friend.id) for friend in friends]))
1: 2
2: 3
3: 

如果要在< User中包含< User 1> 2> 的朋友,我建议在接受从1到2的友谊后再添加一个会员资格

If you want to have <User 1> in <User 2>'s friends, I'd suggest to add another Membership when the friendship from 1 to 2 has been accepted.

在这里,我们假定会员资格只能接受一次,因此添加独特的选项。但是,如果我们有几个会员资格和相同的 from_user ,则将发生以下情况:

Here we assume that a Membership can only be accepted once, so it could be a good idea to add the unique-together option. Nonetheless, if we have several Membership with same from_user, this is what happens:

>>> # <Insert several Membership from one to another User>
>>> Membership.objects.filter(from_user__id=1, to_user__id=2).count()
3
>>> users = User.objects.annotate(member_from__id=F('member_from__id'))
>>> print('User Membership')
... for user in users:
...    print("%4d %10d" % (user.id, user.member_from__id))
User Membership
   1          1
   2          2
   1          3  # User 1 again
   1          4  # User 1 again
   3          None

这篇关于Django queryset附加或注释相关对象字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆