Django ORM:具有至少一组的所有用户

时间:2019-01-25 14:24:21

标签: django django-queryset

我想找到至少属于一组的所有用户。

我找到了解决方法

from django import setup

setup()

from django.contrib.auth.models import User
user_without_group = User.objects.update_or_create(username='user-without-group')[0]
user_without_group.groups.clear()
query = User.objects.filter(groups__isnull=False).values_list('username', flat=True)
print (query.query)
print list(query)
assert user_without_group.username not in query

...但是解决方案不是很好。是否有比groups__isnull=False更明显的解决方案?

更新

为什么我认为此解决方案不好:我认为这并不明显。阅读和理解并不容易。如果您向了解Python但从未使用过django ORM的人展示此内容,我认为他不会立即理解这意味着什么。

User.objects.filter(groups__isnull=False)

5 个答案:

答案 0 :(得分:5)

我不确定您对groups__isnull=False有什么看法;绝对好请注意,尽管它与groups=None完全等效,但是您可能会发现它更好一些。

答案 1 :(得分:2)

您也可以这样做:

Group.objects.values_list('user').distinct('user')

您将仅拥有1个或更多Group的唯一用户。

答案 2 :(得分:1)

User.objects.filter(groups__isnull=False).values_list('username')产生简单的SQL:

SELECT "users_user"."username" FROM "users_user" 
INNER JOIN "users_user_groups" ON ("users_user"."id" = "users_user_groups"."user_id") 
WHERE "users_user_groups"."group_id" IS NOT NULL

docs中显示完全相同的fk上过滤null。

答案 3 :(得分:1)

一种针对SQL实现的较少解决方案是使用Exists子查询或Count

User.objects.annotate(
    has_groups=Exists(
        User.groups.through.objects.filter(
            user=OuterRef('pk'),
        )
    )
).filter(has_groups=True)

User.objects.annotate(
    groups_count=Count('groups'),
).filter(groups__gte=1)

我怀疑这些解决方案的执行速度是否会比groups__isnull=True的内部联接更快。如果m2m字段公开了__exists查找,那么您可以执行filter(groups__exists=True)并避免大部分重复步骤。

答案 4 :(得分:1)

您可以考虑添加一个可读的自定义查找字段,例如Custom Lookupsgroup__at_least_one=True