What do the lt/lte/gt/gte Related Lookups do?

I notice that Django’s relational fields register 7 lookups:

    'in'        : <class 'django.db.models.fields.related_lookups.RelatedIn'>,
    'exact'     : <class 'django.db.models.fields.related_lookups.RelatedExact'>,
    'lt'        : <class 'django.db.models.fields.related_lookups.RelatedLessThan'>,
    'gt'        : <class 'django.db.models.fields.related_lookups.RelatedGreaterThan'>,
    'gte'       : <class 'django.db.models.fields.related_lookups.RelatedGreaterThanOrEqual'>,
    'lte'       : <class 'django.db.models.fields.related_lookups.RelatedLessThanOrEqual'>,
    'isnull'    : <class 'django.db.models.fields.related_lookups.RelatedIsNull'>}

I couldn’t find mention in the docs of what it means to apply lt / lte / gt / gte to a relation - whether it’s a single object or a set. Do they act as set comparison operators? Like, “this Post query is a subset of that Post query”?

What would Post.objects.filter(user__lte=foo) mean?

It compares the pk value to foo. So if Post is the many side of the many-to-one relationship, it would return all Post objects referencing a User object with a pk <= foo.
(Note, you can see what these expressions mean by printing out the internal representation of the query object to see a representation of the SQL that will be generated.)

“…by printing out…”

That’s true, I probably should have done that. str(query.query) is one of my favorite lines in my Django cheatsheet.

BTW - Hard to see much value in less-than/greater-than comparisons with PKs, unless the PK happens to also be a natural key.

Absolutely agree. However, I’m not sure that using this for anything other than the pk would make sense. You can always specify another field by name when necessary, but pk is the only guaranteed-to-be-present field name.

1 Like