如何将查找转换为表达式以在“QuerySet.annotate”中使用?
How to convert a lookup to an expression to use in `QuerySet.annotate`?
题目可能有点晦涩难懂,举个例子。假设我有一个模型:
class TestModel(models.Model):
user = models.ForeignKey(User, ...)
我想要一个包含 has_user
字段的查询集,该字段基本上映射到以下 SQL 查询
select *, user_id is not null as has_user
from app_testmodel
使用 QuerySet.annotate
时如何向 Django 解释这个 has_user
字段?
我知道 Django 有 models.F
、models.Q
、models.lookups
、models.expressions
等概念,但我无法理解如何将它们应用到我的情况。据我所知,这是将 "lookup" 转换为布尔值 "expression" 的问题,其中
A "lookup" 类似于 Django ORM 语言中的 'user_id__isnull'
或 lookups.IsNull(models.F('user_id'))
。
"expression" 类似于 expressions.ExpressionWrapper(?, output_field=models.BooleanField())
。
到目前为止,我只设法将 user_id is not null
表达式转换为 case when user_id is not null then true else false end
,它映射到 Python 代码,如下所示:
from django.db import models
from django.db.models import expressions
# ...
qs = TestModel.objects.all().annotate(has_user=
expressions.Case(
expressions.When(
user__isnull=False,
then=expressions.Value(True),
),
default=expressions.Value(False),
#
# Tell Django the expected type of the field, see `output_field` in
# https://docs.djangoproject.com/en/2.1/ref/models/expressions/
#
output_field=models.BooleanField()))
但这是一个尴尬的解决方法。必须有更好的解决方案:更合适、更简单、更清洁 w.r.t。 Python 代码和生成的 SQL 查询。
关键是使用models.Q
和expressions.ExpressionWrapper
:
qs = TestModel.objects.all().annotate(
has_user=expressions.ExpressionWrapper(
models.Q(user_id__isnull=False),
output_field=models.BooleanField()
)
)
题目可能有点晦涩难懂,举个例子。假设我有一个模型:
class TestModel(models.Model):
user = models.ForeignKey(User, ...)
我想要一个包含 has_user
字段的查询集,该字段基本上映射到以下 SQL 查询
select *, user_id is not null as has_user
from app_testmodel
使用 QuerySet.annotate
时如何向 Django 解释这个 has_user
字段?
我知道 Django 有 models.F
、models.Q
、models.lookups
、models.expressions
等概念,但我无法理解如何将它们应用到我的情况。据我所知,这是将 "lookup" 转换为布尔值 "expression" 的问题,其中
A "lookup" 类似于 Django ORM 语言中的
'user_id__isnull'
或lookups.IsNull(models.F('user_id'))
。"expression" 类似于
expressions.ExpressionWrapper(?, output_field=models.BooleanField())
。
到目前为止,我只设法将 user_id is not null
表达式转换为 case when user_id is not null then true else false end
,它映射到 Python 代码,如下所示:
from django.db import models
from django.db.models import expressions
# ...
qs = TestModel.objects.all().annotate(has_user=
expressions.Case(
expressions.When(
user__isnull=False,
then=expressions.Value(True),
),
default=expressions.Value(False),
#
# Tell Django the expected type of the field, see `output_field` in
# https://docs.djangoproject.com/en/2.1/ref/models/expressions/
#
output_field=models.BooleanField()))
但这是一个尴尬的解决方法。必须有更好的解决方案:更合适、更简单、更清洁 w.r.t。 Python 代码和生成的 SQL 查询。
关键是使用models.Q
和expressions.ExpressionWrapper
:
qs = TestModel.objects.all().annotate(
has_user=expressions.ExpressionWrapper(
models.Q(user_id__isnull=False),
output_field=models.BooleanField()
)
)