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_name
在 authors
值中:
(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')))
)
我有两个 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_name
在 authors
值中:
(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')))
)