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 Source
s 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 Source
s 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
datereported
itself, or the correspondingSource
object?– Willem Van Onsem
Jul 1 at 17:25