Opened 16 years ago
Closed 14 years ago
#8378 closed (fixed)
Generic views cache-like behavior
Reported by: | ovidiup | Owned by: | nobody |
---|---|---|---|
Component: | Documentation | Version: | dev |
Severity: | Keywords: | generic view cache | |
Cc: | semente@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Sometimes the generic views will behave like they are caching the data from the queryset argument. This happens when the queryset is passed through the info_dict dictionary and the queryset is filtered using a callable. The result of the callable is cached in the where clause. When the generic view is executed the callable from the filter is not invoked again.
See this blog post for more details, example and work-around: http://pascut.com/2008/08/16/django-generic-views-cache-behavior/
One of the following things should be done:
- The result of the callables should not be cached in the where clause; the callables should be invoked just before the query is sent to the database or
- The documentation should mention this as a limitation
Change History (8)
comment:1 by , 16 years ago
Cc: | removed |
---|
comment:2 by , 16 years ago
Component: | Generic views → Documentation |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:3 by , 16 years ago
Cc: | added |
---|
comment:4 by , 16 years ago
milestone: | 1.0 maybe → post-1.0 |
---|
comment:5 by , 16 years ago
Couldn't we make the generic views check if the queryset parameter is callable, and if so, call it per request. So an example would be:
url(r'$', 'django.views.generic.list_detail.object_list', {'queryset':ClassifiedCategory.objects.all(),}, 'classifieds'),
would then become:
url(r'$', 'django.views.generic.list_detail.object_list', {'queryset':ClassifiedCategory.objects.all,}, 'classifieds'),
Furthermore, the queyset is not callable. Alternatively, the generic view could do a hasattr(queryset, '_clone') and call based off that.
comment:7 by , 15 years ago
Ignore my previous comment. Seems that is a different bug and have been fixed, this issue deals more with querysets. See code below:
>>> from django.contrib.auth.models import User >>> import datetime, time >>> qs = User.objects.all().filter(last_login__lte=datetime.datetime.now) >>> qs._clone().query.as_sql() ('SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`last_login` <= %s ', (u'2009-06-26 16:44:41',)) >>> time.sleep(5) >>> qs._clone().query.as_sql() ('SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`last_login` <= %s ', (u'2009-06-26 16:44:41',))
As you can see the query didn't change even though we passed a callable in and used _clone. It seem the queryset allows callables to be passed but are immediately evaluated. The callables should be lazy in their evaluation and the value return by a callable should not be passed on when it is clone, rather the callable itself should be passed
comment:8 by , 14 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Function-based generic views were deprecated by the introduction of class-based views in [14254]. Class-based views should solve this problem.
A clarification in the documentation might be worthwhile here if it can be written so that it's not too long (this is an edge-case so should be very incidental to the main description of things). Something to the effect that callables in filters are evaluated exactly once. We can't really change things so that that doesn't happen, since it would only be to support a situation like this and would introduce a lot of extra complexity.