I have discovered through trial and error that DurationFields can be filtered with formatted strings that are more powerful than just “hh:mm:ss”. I have been unable to find a formal spec on what works and what doesn’t. For example, say I have a model named Animal
with an age
field:
age = models.DurationField(
null=True,
blank=True,
validators=[MinValueValidator(timedelta(seconds=0))],
help_text="The age of the animal at the time of sample collection.",
)
We enter the value x
in the DB using timedelta(weeks=x)
. And we have an advanced search interface where the user has been entering a value using the “hh:mm:ss” format, which essentially is executed like:
# 14 weeks
search_term = "2352:00:00"
Animal.objects.filter(age__gt=search_term)
We had tried strings like 98-00:00:00
, as I’d seen that format somewhere, but it didn’t work. I’m finally sitting down to flesh the strategy out and give the user a units select list and I have tried various things to determine that roughly the following pattern is compatible:
[n{c[enturies],decades,y[ears],months,w[eeks],d[ays]}{:,\,}[ ]]*hh[h[ours]]:mm[m[inutes]]:ss[.f][s[econds]]
So for example, I can get correct results for ORM filters like:
In [64]: Animal.objects.filter(age__gt="97d:24h").values_list("age", flat=True)
Out[64]: <QuerySet [datetime.timedelta(days=105), datetime.timedelta(days=105), datetime.timedelta(days=105), datetime.timedelta(days=105), datetime.timedelta(days=105), datetime.timedelta(days=105)]>
In [65]: Animal.objects.filter(age__exact="97 d,24 h").values_list("age", flat=True)
Out[65]: <QuerySet [datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98), datetime.timedelta(days=98)]>
I couldn’t find shorter strings for indicating “decades” or “months”.
Note, I can supply strings and I don’t need to create timedelta objects (though if I did, those do work as well). But I’m interested is learning the direct string format that can be supplied to the filter.