Django QS 按嵌套注释字段过滤

Django QS filter by nested annotated field

我有两个 Django 模型:

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


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

现在我想通过他们的 author 全名 (first_name + last_name) 添加过滤 Book。我添加了 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_nameauthors 值中:

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

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

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

像这样:

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')))
)