I have the following models:
class Collection(models.Model):
# some fields here ...
class Entry(models.Model):
collection = models.ForeignKey(Collection, reverse_name="entries")
start_time = models.DateTimeField()
end_time = models.DateTimeField()
Now I want to query all Collections that have at least one Entry associated which I do with (quite quirky, I think):
collections_qs = Collection.objects.annotate(
entry_count=Count('entries')
).filter(entry_count__gt=0)
Which works quite well. But I want to combine this query with a date/time window search given by the two datetimes start and end. What I’ve come up with was:
if start:
collections_qs = collections_qs.filter(entries__start_time__gte=start)
if end:
collections_qs = collections_qs.filter(entriess__end_time__lte=end)
But that just rearranges the order of the returned Collections but not the content. How can I achieve the date/time search (preferably with just one query)?
For reverse FK (and ManyToMany fields too), there is a difference between
.filter(a=b, x=y)and.filter(a=b).filter(x=y)(see doc).What you need when you have both
startandendconditions is thefilter(.,.)one that will get you theCollectionsthat have at least oneEntrythat verifies both condition.Also,
Collection.objects.filter(entries__isnull=False).distinct()seems more readable than.annotate(entry_count=Count('entries')).filter(entry_count__gt=0).Finally, when you have at least one condition on
entries, you don’t need to have any filter to check for the existence of such entries.