Django: Filtering datetime field by *only* the year value?
Question:
I’m trying to spit out a django page which lists all entries by the year they were created. So, for example:
2010:
-
Note 4
-
Note 5
-
Note 6
2009:
-
Note 1
-
Note 2
-
Note 3
It’s proving more difficult than I would have expected. The model from which the data comes is below:
class Note(models.Model):
business = models.ForeignKey(Business)
note = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'client_note'
@property
def note_year(self):
return self.created.strftime('%Y')
def __unicode__(self):
return '%s' % self.note
I’ve tried a few different ways, but seem to run into hurdles down every path. I’m guessing an effective ‘group by’ method would do the trick (PostGres DB Backend), but I can’t seem to find any Django functionality that supports it. I tried getting individual years from the database but I struggled to find a way of filtering datetime fields by just the year value. Finally, I tried adding the note_year @property but because it’s derived, I can’t filter those values.
Any suggestions for an elegant way to do this? I figure it should be pretty straightforward, but I’m having a heckuva time with it. Any ideas much appreciated.
Answers:
You can use django.views.generic.date_based.archive_year or use year field lookup.
Either construct custom SQL or use
date_list = Note.objects.all().dates('created', 'year')
for years in date_list:
Note.objects.filter(created__year = years.year)
This is the way it is done in date based generic views.
We can improve the filter using a list of years, then check if the year of creation is on that.
With that list, the database will be called once one time, because the Note.objects.filter
will runs outside the for
loop.
Something like this:
notes = Note.objects.all().dates('created', 'year')
years = [note.year for note in notes]
Note.objects.filter(created__year__in = years)
I’m trying to spit out a django page which lists all entries by the year they were created. So, for example:
2010:
-
Note 4
-
Note 5
-
Note 6
2009:
-
Note 1
-
Note 2
-
Note 3
It’s proving more difficult than I would have expected. The model from which the data comes is below:
class Note(models.Model):
business = models.ForeignKey(Business)
note = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'client_note'
@property
def note_year(self):
return self.created.strftime('%Y')
def __unicode__(self):
return '%s' % self.note
I’ve tried a few different ways, but seem to run into hurdles down every path. I’m guessing an effective ‘group by’ method would do the trick (PostGres DB Backend), but I can’t seem to find any Django functionality that supports it. I tried getting individual years from the database but I struggled to find a way of filtering datetime fields by just the year value. Finally, I tried adding the note_year @property but because it’s derived, I can’t filter those values.
Any suggestions for an elegant way to do this? I figure it should be pretty straightforward, but I’m having a heckuva time with it. Any ideas much appreciated.
You can use django.views.generic.date_based.archive_year or use year field lookup.
Either construct custom SQL or use
date_list = Note.objects.all().dates('created', 'year')
for years in date_list:
Note.objects.filter(created__year = years.year)
This is the way it is done in date based generic views.
We can improve the filter using a list of years, then check if the year of creation is on that.
With that list, the database will be called once one time, because the Note.objects.filter
will runs outside the for
loop.
Something like this:
notes = Note.objects.all().dates('created', 'year')
years = [note.year for note in notes]
Note.objects.filter(created__year__in = years)