Opened 19 years ago
Closed 19 years ago
#1502 closed enhancement (wontfix)
Make (?P) url parameters available to filter a generic view's queryset.
Reported by: | Owned by: | Jacob | |
---|---|---|---|
Component: | Generic views | Version: | magic-removal |
Severity: | normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Example Problem:
1) http://example.com/users/ - lists all the users.
2) http://example.com/users/(?P<mystr>[a-z]+)/ - For given string, list all the users with a username beginning with that string.
(1) is a simple generic view. However, one currently must write a custom view to come up with a QuerySet for (2). What we could do is just take the generic view used for (1) and filter that QuerySet down more.
The code listed here is an example solution using a custom wrapper to the object_list generic view. A real solution would patch the generic views. 'myproject.object_list' (shown here) differs from the generic object_list by two items in its method signature: extra_lookup_kwargs={} and kwargs; some of its code can be used to filter the queryset.
myproject/urls.py
info_dict = { 'queryset': MyModel.objects.all(), 'extra_lookup_kwargs': { 'mystr': 'name__istartswith'} } urlpatterns = patterns('', (r'^users/$', 'myproject.views.object_list', info_dict), (r'^users/(?P<mystr>.+)/$', 'myproject.views.object_list', info_dict), )
myproject/views.py:
from django.template import loader from django.views.generic import list_detail def object_list(request, queryset, paginate_by=None, allow_empty=False, template_name=None, template_loader=loader, extra_context={}, context_processors=None, template_object_name='object', extra_lookup_kwargs={}, **kwargs): extra_lookup_dict = {} for param in kwargs: if param in extra_lookup_kwargs: extra_lookup_dict[extra_lookup_kwargs[param]] = kwargs[param] if len(extra_lookup_dict) > 0: newqueryset = queryset.filter(**extra_lookup_dict) else: newqueryset = queryset return list_detail.object_list(request=request, queryset=newqueryset, paginate_by=paginate_by, allow_empty=allow_empty, template_name=template_name, template_loader=template_loader, extra_context=extra_context, context_processors=context_processors, template_object_name=template_object_name)
Change History (3)
comment:1 by , 19 years ago
comment:2 by , 19 years ago
The custom view code for your specific case looks like this:
def my_object_list(request, mystr): mymodels = MyModel.objects.filter(name__istartswith=mystr) return list_detail.object_list(request, mymodels, extra_context={'foo':'bar'}, paginate_by=10, allow_empty='True', template_name='mymodels/index')
Is that so hard? Remember, you don't have to make the function have the same interface as the generic view -- you simply take the parameters that were in your urls.py and put them in your view function.
Trying to stuff everything into generic views makes them less useful, since the interface becomes more and more complex. There are lots of tickets similar to this one, trying to get generic views to do one more thing (i.e. a custom tweak). If you added them all it would be ridiculous. Generic views are already very easy to wrap, with very few lines of code. Your my_queryset_modifier() function is almost twice as long as the code above.
So I would be -1 on this.
comment:3 by , 19 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Marking this as a wontfix for the reasons Luke mentioned in his previous comment.
Thinking about the above... Instead of hardcoding logic for the filter, it may be better to allow the end user to use their own queryset_modifier method.
#The developer will have to coordinate the ?P<names> and the extra keys in info_dict so they don't overlap, since they'll both be passed in as kwargs to the object_list. This will be done when the queryset_modifier function is defined, since the conflicts will be settled in that function's parameter listing.