4

我最近将 Django 更新到最先进的版本 1.11rc1,因为那里引入了子查询功能。

现在,假设这是我的用例:我有以下模型 - 用户、组和权限。所以,我有一些我可以分组的用户(例如管理员组)和权限 - 这是可以做一些事情的用户列表(例如,我有用户 A、用户 B 和可以创建新用户的管理员)。我现在要做的是有效地显示所有权限,其中包含许多用户。所以换句话说,我想创建一个 QuerySet,它会返回有关权限的所有信息并计算每个权限的用户数。解决此问题的第一个显而易见的方法是创建一个get_user_countPermission 模型的方法,它将从我的 ManyToMany 关系中返回所有用户,但这将需要每个 Permission 至少 1 个额外的查询,这对我来说是不可接受的,因为我计划拥有很多 Permission。这是我想使用的地方Subquery

所以,澄清一下 - 这是models.py:

class User(models.Model):
    name = models.CharField(max_length=20)

class Group(models.Model):
    users = models.ManyToManyField(User)

class Permission(models.Model):
    users = models.ManyToManyField(User)
    groups = models.ManyToManyField(Group)

我想创建一个查询集,它将返回所有权限,里面有很多用户。举例来说,假设我只想包含属于我的组的用户 - 所以我会有这样的事情:

groups = Group.objects.filter(permission=OuterRef('pk'))
users = User.objects.filter(group__in=groups)
queryset = Permission.objects.annotate(
    user_no=Subquery(users.annotate(c=Count('*')).values('c'))
)

这里的问题是我OuterRef无法解决“子查询的过滤器过滤器”中使用的问题:

This queryset contains a reference to an outer query and may only be used in a subquery.

虽然,当我使用另一个子查询来获取组时:

groups = Group.objects.filter(permission=OuterRef(OuterRef('pk')))
users = User.objects.filter(group__in=Subquery(groups))
queryset = Permission.objects.annotate(
    user_no=Subquery(users.annotate(c=Count('*')).values('c'))
)

我在第一行得到一个错误:

int() argument must be a string, a bytes-like object or a number, not 'OuterRef'

其余的行无关紧要,对错误没有影响。奇怪的是,文档中出现了完全相同的语法:https ://docs.djangoproject.com/en/dev/ref/models/expressions/#django.db.models.OuterRef

问题是:我做错了什么?或者如何以其他方式(尽管有效)实现我想要的?

4

1 回答 1

2

好吧,这是 Django 中的一个错误:https ://github.com/django/django/pull/9529

OuterRef(OuterRef('pk'))我通过使用注释排除双深度 ( ) 来修复它:

return self.annotate(category=Subquery(
    # this is the "inner" subquery which is now just an annotated variable `category`
    Category.objects.filter(offer=OuterRef('pk'))[:1].values('pk')
)).annotate(fs=Subquery(
    # this is the "outer" subquery; instead of using subquery, I just use annotated `category` variable
    Category.objects.filter(pk=OuterRef('category')).values('slug')
))

希望能帮助到你 :)

于 2018-01-29T14:12:16.617 回答