#11629 closed Cleanup/optimization (fixed)
Deprecate callable QuerySet filter arguments
Reported by: | harrym | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | bmispelon@… | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Apologies if I've missed this somewhere, but I couldn't find anything in the documentation that states that the keyword arguments passed to a QuerySet's
filter method may be callable. This is useful in cases such as when QuerySets
are constructed for generic views, and you want to filter by a time relative to now. This appears in the code in django/db/models/sql/query.py, line 1546.
Change History (12)
comment:1 by , 15 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → Cleanup/optimization |
comment:3 by , 13 years ago
UI/UX: | unset |
---|
comment:5 by , 12 years ago
Cc: | added |
---|
The code has moved around a bit since the report but the feature still exists: https://github.com/django/django/blob/f403653cf146384946e5c879ad2a351768ebc226/django/db/models/sql/query.py#L1074
It's still not documented anywhere that I could find but more interestingly, I couldn't find any tests for it either.
Note that the feature doesn't only apply to Queryset.filter
but also to Queryset.exclude
, Queryset.get
, and Q objects
.
Interestingly, it also sorta works for get_or_create
but only for the get part. If the object doesn't exist in the database, then django will set the model field's value to the callable and things will most likely break when attempting to save to the database.
I think a good place to document this would be in the "Field lookups" paragraph of the queryset API reference page: https://docs.djangoproject.com/en/dev/ref/models/querysets/#id4.
comment:6 by , 12 years ago
I see it mentioned in the tutorials - https://docs.djangoproject.com/en/dev/intro/tutorial05/
Notice that we use a callable queryset argument, timezone.now, which will be evaluated at request time. If we had included the parentheses, timezone.now() would be evaluated just once when the web server is started.
comment:7 by , 12 years ago
It looks like the feature is "broken" since callable arguments are evaluated when the queryset is built, not when it's evaluated.
This means (if I understand it right), that doing queryset.filter(foo=some_callable)
is basically the same as doing queryset.filter(foo=some_callable())
, which makes this feature less useful.
This was discovered in ticket #20241.
I think the feature would be useful but after discussing it on IRC, it seems it might be quite tricky to get it to work.
comment:9 by , 11 years ago
Has patch: | set |
---|
On top of being undocumented, that feature is also untested (full test suite still passed after removing the two lines that call the value if it's callable).
Plus, as mentionned on #20241, this feature is going to be tricky to implement in a useful way.
Consequently, I propose to remove the feature altogether (going through the usual deprecation path).
Here's a PR with docs and some tests: https://github.com/django/django/pull/2091
comment:10 by , 11 years ago
Component: | Documentation → Database layer (models, ORM) |
---|---|
Summary: | Callable QuerySet filter arguments not mentioned in documentation → Deprecate callable QuerySet filter arguments |
Triage Stage: | Accepted → Ready for checkin |
comment:11 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Change UI/UX from NULL to False.