Get minimum of related model date field (django)
Get minimum of related model date field (django)
I have the two following classes:
class Incident(models.Model):
iid = models.IntegerField(primary_key=True)
person = models.ForeignKey('Person', on_delete=models.SET_NULL, null=True)
class Source(models.Model):
sid = models.IntegerField(primary_key=True)
incident = models.ForeignKey('Incident', on_delete=models.SET_NULL, null=True)
url = models.TextField(validators=[URLValidator()])
datereported = models.DateField(null=True, blank=True)
I want to create a field within the Incident that will pull the minimum datereported of related sources. Is this best done in the model, or in the template? Unsure what best practice is, or how to execute in this case.
datereported
Source
the datereported itself! but i am curious about returning the source object too. is it the same process?
– NBC
Jul 1 at 17:28
2 Answers
2
Is this best done in the model, or in the template?
Well a template should - strictly speaking - not contain business logic. It should contain render logic. It should thus specify how something should be visible, not what should be visible. So it dos not really belong in the template layer, only in the model layer.
You can obtain the smallest datereported with:
datereported
from django.db.models import Min
class Incident(models.Model):
iid = models.IntegerField(primary_key=True)
person = models.ForeignKey('Person', on_delete=models.SET_NULL, null=True)
@property
def first_reporteddate(self):
return self.source_set.aggregate(first=Min('datereported'))['first']
This will ignore Sources with datereported set to None (so if there are multiple sources, it takes the smallest datereported that is not None). If there are no Source with a datereported not equal to None, or no related Sources at all, it will return None however, since the minimum of an empty set is considered to be NULL (in SQL, or None in Python/Django).
Source
datereported
None
datereported
None
Source
datereported
None
Source
None
NULL
None
You can then use this in the template like:
{{ some_incident.first_reporteddate }}
In case you want the entire object, you can use self.source_set.order_by('datereported').first() which will give you the earliest related Source instance. But this will have a (quite) small impact on performance (it will take a bit longer). In that case Django will fetch all columns into memory first. If you thus only need one column, this will result in the fact that you did some useless serialization (at the database end) and deserialization (at the Python end).
self.source_set.order_by('datereported').first()
Source
You can use model's property for this:
class Incident(models.Model):
iid = models.IntegerField(primary_key=True)
person = models.ForeignKey('Person', on_delete=models.SET_NULL, null=True)
@property
def first_datereported(self):
first_source = self.source_set.order_by('datereported').first()
if first_source:
return first_source.datereported
In template or in any other part of code you can use first_datereported as normal model's field:
first_datereported
{{ incident_instance.first_datereported }}
i think you need to add the check for
None in last_source– Bear Brown
Jul 1 at 17:27
None
last_source
@BearBrown you are right. Thanks!
– neverwalkaloner
Jul 1 at 17:31
Won't this return the first
datereported? In that case first_datereported probably is a better name (or earliest_reporteddate).– Willem Van Onsem
Jul 1 at 17:31
datereported
first_datereported
earliest_reporteddate
@WillemVanOnsem sure, thank you!
– neverwalkaloner
Jul 1 at 17:33
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Do you mean the
datereporteditself, or the correspondingSourceobject?– Willem Van Onsem
Jul 1 at 17:25