I found this question very interesting. So I played with the console for a while.
I followed the links provided by @Ivan and got the following:
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')
This should indicate your year as a string.
Note: this will work if in _date you get something like this: u'2015-08-24 09:45:16' , if you get another row, you can change the indices in Substr('_date', 1, 4) . You can see which string you get in _date by adding it to .values('_date', 'publish_year') .
Hope this helps.
Additionally:
This is the result I got:
[{'date': datetime.datetime(2015, 8, 24, 9, 45, 16), 'date3': u'2015', 'date2': u'2015-08-24 09:45:16'}, ...]
In this case, date3 is the final result for me.
EDIT:
Generated 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