过滤营地 我正在尝试优化此过滤过程,因为获取所有营地然后在Python中过滤它对于我的用例来说太慢了,并且随着更多的时间在必须过滤掉的营地数量上,这将继续增加。
我提出的解决方案为我提供了所需的结果,但是生成的SQL查询具有多个我不需要的子查询的多次运行。我想避免使用RAWSQL进行此操作,并想找到一种使用Django ORM函数实现所需结果的方法。我正在使用PostgreSQL,并且可以使用其提供的任何内置功能。我使此功能获得了我需要的营地
def get_future_camps():
"""
Retrieves all Camp objects where the latest date in the 'dates' JSONB field is today or in the future.
Returns a QuerySet with only relevant fields.
"""
today_str = now().date().isoformat()
camps_with_max = Camp.objects.annotate(
max_date=Subquery(
Camp.objects.filter(
id=OuterRef("id")
).annotate(
extracted_dates=JsonbArrayElementsText(F("dates"))
).values_list("extracted_dates", flat=True).order_by("-extracted_dates")[:1]
)
)
return camps_with_max.filter(
max_date__gte=today_str
).only("id", "pk")
# This only works for Postgres
class JsonbArrayElementsText(Func):
"""
A custom function to extract elements from a JSONB array as text.
"""
function = 'jsonb_array_elements_text'
output_field = CharField()
this生成此SQL查询
SELECT "my_project_camp"."id",
(
SELECT jsonb_array_elements_text(U0."dates") AS "extracted_dates"
FROM "my_project_camp" U0
WHERE U0."id" = "my_project_camp"."id"
ORDER BY 1 DESC
LIMIT 1
) AS "max_date"
FROM "my_project_camp"
WHERE (
SELECT jsonb_array_elements_text(U0."dates") AS "extracted_dates"
FROM "my_project_camp" U0
WHERE U0."id" = "my_project_camp"."id"
ORDER BY 1 DESC
LIMIT 1
) >= '''2025-03-08'''
该使用相同的子查询两次获得“ max_date”。查找之后,我发现在
WHERE
之前对
SELECT
子句进行了评估,因此您不能在
WHERE
子句中使用别名我的问题是:有没有办法删除额外的子查询?我正在使用
only
,所以我不需要在过滤器本身之外使用max_date字段,而这样做的全部要点是优化获得未来的营地
我有camp模型,该模型存储在JSON领域中的一系列字符串。
Revisit建模。
json blobs是一个好主意[django-antipatterns]如果您需要与斑点的一部分一起工作,这是违反了第一个正常形式(1nf)
[wiki]
[wiki]与以下型号一起工作:
class Camp(models.Model):
# no dates
# …
pass
class CampDate(models.Model):
camp = models.ForeignKey(Camp, on_delete=models.PROTECT)
date = models.DateField()
也保证date
是一个有效的日期,并将将此更紧凑存储在数据库中。
并检索:
from django.utils.timezone import now
today_str = now().date()
Camp.objects.filter(campdate__date__gte=today_str).distinct()