从DateTimeField中提取年份的正确方法是什么?
给出的例子:
class Article(models.Model):
title = models.CharField(_('title'), max_length=250)
slug = models.SlugField(_('slug'), max_length=250, unique=True, default='', blank=True)
content = models.TextField(_('content'))
author = models.ForeignKey(settings.AUTH_USER_MODEL)
categories = models.ManyToManyField(Category)
tags = models.ManyToManyField(Tag)
created = models.DateTimeField(_('created'), default=timezone.now)
publish_date = models.DateTimeField(_('publish date'), blank=True, null=True)
STATUS_ARTICLE = (
('DRAFT', _('draft')),
('PUBLISHED', _('published'))
)
status = models.CharField(_('status'), max_length=100, choices=STATUS_ARTICLE, default='DRAFT')
class ExtractMonth(Func):
template = "EXTRACT(MONTH FROM %(expressions)s)"
def __init__(self, *expressions, **extra):
extra['output_field'] = models.SmallIntegerField()
super().__init__(*expressions, **extra)
尝试获取所有年份的列表以及每年的文章数量:
result = Article.objects.filter(status='PUBLISHED').annotate(Year=ExtractYear('publish_date')).values('Year').annotate(dcount=Count('Year'))
这会导致以下错误:
near "FROM": syntax error
生成的查询是:
SELECT EXTRACT(YEAR FROM "articles_article"."publish_date") AS "Year", COUNT(EXTRACT(YEAR FROM "articles_article"."publish_date")) AS "dcount" FROM "articles_article" WHERE "articles_article"."status" = PUBLISHED GROUP BY EXTRACT(YEAR FROM "articles_article"."publish_date"), "articles_article"."created" ORDER BY "articles_article"."created" DESC
答案 0 :(得分:3)
这就是我最终做的事情。 Gocht的解决方案看起来应该可行,但我遇到了问题(Django 1.10,SQLite),Django处理结果。我不想使用RawSQL
,但这是我唯一能够工作的。
try:
from django.db.models.functions import ExtractYear
except ImportError:
from django.db.models.expressions import RawSQL
qs = Article.objects.filter(...)
try:
# Django >= 1.10
qs = qs.annotate(Year=ExtractYear('publish_date'))
except NameError:
# Django < 1.10
qs = qs.annotate(Year=RawSQL(
"CAST(SUBSTR('table_name'.'publish_date', 1, 4) AS integer)",
()
))
results = qs.values('Year').annotate(dcount=Count('Year'))
这使Year
成为整数,而不是字符串;如果你想要一个字符串,请删除CAST(... AS integer)
。
您需要将table_name
更改为您的模型数据库表。
我不确定except NameError
是解决这个问题的最佳方法,但我无法确定如何更好地处理这个问题。
答案 1 :(得分:0)
我觉得这个问题很有意思。所以我在控制台玩了一段时间。
我按照@Ivan提供的链接获得了这个:
NSURLSessionTaskDelegate -> URLSession:task:didCompleteWithError:
这应该把你的年份作为一个字符串。
注意:如果在from django.db.models import F, Func
from django.db.models.functions import Substr
Article.objects.filter(...).annotate(_date=Func(F('publish_date'), function='LOWER'))
.annotate(publish_year=Substr('_date', 1, 4))
.values('publish_year')
中你得到这样的内容,这将有效:_date
,如果你得到一个不同的字符串,你可以更改u'2015-08-24 09:45:16'
中的索引。您可以通过在Substr('_date', 1, 4)
中添加_date
来查看.values('_date', 'publish_year')
中获得的字符串类型。
我希望这会有所帮助。
额外:
这是我得到的结果:
[{'date': datetime.datetime(2015, 8, 24, 9, 45, 16), 'date3': u'2015', 'date2': u'2015-08-24 09:45:16'}, ...]
在这种情况下,date3
对我来说是最终结果。
编辑:
生成的SQL:
>>> print MyModel.objects.all().annotate(date2=Func(F('date'), function='LOWER')).annotate(date3=Substr('date2', 1, 4)).query
SELECT `app_model`.`id`, `app_model`.`date`, LOWER(`app_model`.`date`)
AS `date2`, SUBSTRING(LOWER(`app_model`.`date`), 1, 4)
AS `date3` FROM `app_model` ORDER BY `app_model`.`created` ASC
答案 2 :(得分:0)
Django具有内置函数TruncYear
尝试一下
result = Article.objects.filter(status='PUBLISHED').annotate(Year=TruncYear('publish_date'))