【问题标题】:Django QS filter by nested annotated fieldDjango QS按嵌套注释字段过滤
【发布时间】:2021-07-07 14:40:00
【问题描述】:

我有两个Django 模型:

class User(models.Model):
    first_name = ...
    last_name = ...


class Book(models.Model):
    authors = models.ManyToManyField(User)

现在我想通过 author 的全名 (first_name + last_name) 添加过滤 Books。我添加了FilterSet,其逻辑如下:

qs_prefetched = queryset.prefetch_related(
    Prefetch("authors", User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name')))
).all().filter(authors__full_name__icontains=value)

当我尝试以这种方式过滤时,出现以下错误:

django.core.exceptions.FieldError: Related Field got invalid lookup: full_name

但字段 full_name 在 authors 值中:

(Pdb) qs_prefetched[1].authors.all()[0].full_name
'Ke Xu'

谁能告诉我我错过了什么? 提前致谢。

【问题讨论】:

    标签: django django-orm


    【解决方案1】:

    您的注释在预取的查询集上。您还需要注释基本查询集,以便根据需要对其进行过滤。

    类似这样的:

    qs_prefetched = queryset.prefetch_related(
        Prefetch("authors", User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name')))
    ).annotate(
        calc_full_name=Concat('authors__first_name', Value(' '), 'authors__last_name')
    ).filter(calc_full_name__icontains=value)
    

    诚然,我怀疑上面是否能完全按照您的意愿工作,因为它试图注释多对多关系。

    另一种选择是使用Subquery and Exists 过滤器,您可以在其中查找与名称匹配的用户,该过滤器对存在检查。

    user_subquery = User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name').filter(
        full_name__icontains=value,
        id=OuterRef('author_id'), # This depends on your models.
    )
    qs_prefetched = queryset.filter(Exists(user_subquery)).prefetch_related(
        Prefetch("authors", User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name')))
    )
    

    【讨论】:

    • 第一种方法不起作用,annotate 仅连接来自 M2M 的第一个对象的字段。但第二个工作正常。没想过过滤用户然后使用Subquery和Exists。
    猜你喜欢
    • 2011-06-04
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    相关资源
    最近更新 更多