Django - 按最大(日期)年份过滤查询集
Posted
技术标签:
【中文标题】Django - 按最大(日期)年份过滤查询集【英文标题】:Django - Filter a queryset by Max(date) year 【发布时间】:2014-03-10 12:25:19 【问题描述】:我想知道我是否可以在单个查询中获得某个模型的所有对象,其日期年份等于模型的 Max('date') 年份。例如,使用Aggregation Django Docs中的模型,如何获得最近发布的Book
当年发布的所有Book
s?
文档中的所有示例均按立即值 (pubdate__year=2006
) 进行过滤,但我需要在同一查询中对同一对象使用计算值。
当然,我可以通过执行两个查询来做到这一点:一个用于获取最大年份,第二个用于过滤该年份,但我认为应该可以在单个查询中完成。只是我还没弄明白。
感谢您的帮助!
编辑:
由于你们中的一些人给出了类似的答案,我正在写这个更新,以便更好地理解我的问题。
这是我的模型:
class Expo(models.Model):
class Meta:
verbose_name= _('Expo')
verbose_name_plural = _('Expos')
name = models.CharField(max_length=255)
place = models.CharField(max_length=255, null=True, blank=True)
date = models.DateField()
bio = models.ForeignKey(Bio, related_name='expos')
我需要“我的数据库中存储的Expo
s 列表中最近一年发生的所有Expo
s”
为了解决这个问题,我正在这样做:
from django.db.models import Max
max_year = Expo.objects.all().aggregate(Max('date'))['date__max'].year
expos = Expo.objects.filter(date__year=max_year)
但是,据我所知,它对数据库执行了两个查询。我想要一个让我得到相同结果但执行单个查询的表达式。
我已经按照建议尝试了:
Expo.objects.annotate(max_year=Max('date__year')).filter(date__year=F('max_year'))
但得到错误:
FieldError: Join on field 'date' not permitted. Did you misspell 'year' for the lookup type?
我也试过了:
Expo.objects.annotate(max_date=Max('date')).filter(date__year__gte=F('max_date__year'))
但我得到了错误:
FieldError: Cannot resolve keyword 'max_date' into field. Choices are: bio, date, id, items, name, place, max_date
请注意,它表示无法解析'max_date'
,但它显示在选项中。很奇怪。
再次感谢您的帮助! :)
【问题讨论】:
到目前为止你尝试过什么?如果您在查找文档时遇到问题,以下是您正在尝试执行的操作的示例:docs.djangoproject.com/en/dev/topics/db/aggregation/… 需要注意的是必须结合F()
表达式使用:docs.djangoproject.com/en/dev/topics/db/queries/…
谢谢! F()
对象似乎是我需要的,但更大的问题是我需要比较年份,而不是日期。我按照以下答案中的建议进行了尝试:Expo.objects.annotate(max_date=Max('date')).filter(date__gte=F('max_date'))
(请注意__gte
)但它返回的不是预期的实例(日期在最大日期之前)。我也试过Expo.objects.annotate(max_date=Max('date')).filter(date__year__gte=F('max_date__year'))
,但得到了这个奇怪的错误:FieldError: Cannot resolve keyword 'max_date' into field. Choices are: bio, date, id, items, name, place, max_date
在单个查询中执行语句不会提高性能。另外,请记住,而不是Max
agregation,您可以通过-date
获得第一个模型排序。对我来说,两句话更清晰、更易读、更快速地拆分代码。如果您不相信,请尝试用一个与 SQL 品牌无关的句子来编写您的查询。
@danihp:你能解释一下为什么它不会提高性能吗?这正是我担心的。谢谢!
【参考方案1】:
在单个查询中执行语句并不能保证提高性能,如果您尝试为您的要求编写一个不可知的 RDBMS 品牌 SQL 单句,这很容易理解。此外,您失去了可读性。
在我看来,您可以在这种方法中看到优雅的解决方案:
-
按日期获取最后一个
Expo
。
做一个简单的过滤查询。
对于您的代码:
max_year = Expo.objects.latest('date').date.year
expos = Expo.objects.filter(date__year=max_year)
记住您可以cache max_year,也可以在date
之上创建一个DESC
索引会有所帮助。
【讨论】:
谢谢!当被问到这个问题时,这就是我所关心的。带有缓存和上下文处理器的东西,也是一个非常好的主意。谢谢!【参考方案2】:以下是您如何使用 Annotation 和 F 对象的组合来做某事
过滤最大日期:
ModelClass.objects.annotate(max_date=Max('pubdate')).filter(pubdate=F('max_date'))
过滤最大日期的年份:
max_date = ModelClass.objects.latest("pubdate").pubdate
published_objs = ModelClass.objects.filter(pubdate__year=max_date.year)
似乎没有办法在单个查询中过滤 Max(date.year)。正如@danihp 所提到的,即使是单个查询也不能保证性能。
【讨论】:
嗨!在测试您的建议后,它似乎没有返回我所期望的。首先,您的建议应该返回字段date
等于max_date
的对象,我需要字段date
的年份等于max_date
年份的对象。其次,当我在manage.py shell
中测试它时,它返回(我认为)所有对象,而忽略了过滤器。你测试了吗?它对你有用吗?感谢您的帮助!
更新了过滤年份的答案。答案基于我对 django 的理解(未经测试,因为我没有与您类似的设置)
这将在 django 1.6 上引发:FieldError: Join on field 'pubdate' not permitted. Did you misspell 'year' for the lookup type?
。请在发布前进行测试。
请修正你的答案并通知我,以消除我的反对票。
@danihp 我参考了django 1.6 docs。请您告诉我错误,因为我仍然不明白错误的原因。【参考方案3】:
Throoze 试试这个...
queryset=Expo.objects.annotate(max_date=Max('date'))
queryset1=queryset.values().filter(date__gte=F('max_date'))
【讨论】:
嗨!它应该在values()
之后有括号,并且由于某种奇怪的原因,它还返回日期小于 max_date 的值。而且,如上所述,如果我尝试比较年份(这是我需要的),我会不断收到此错误:FieldError: Cannot resolve keyword 'max_date' into field. Choices are: bio, date, id, items, name, place, max_date
。无论如何感谢您的帮助:)
我们有旧日期的功能吗?以上是关于Django - 按最大(日期)年份过滤查询集的主要内容,如果未能解决你的问题,请参考以下文章