In UNIX way, each view should solve single task. This is good idea, but sometimes we need to mix logic of different views on same page. Filter, sort, paginate, or, for example, add comment on product page. In this article I'll show how we can mix such multiple views.
We can write views as decorators.
Simplified filtration can look like this:
from django.views.generic.list_detail import object_list
def filtered_list(request, filterset_class, queryset, *args, **kwargs):
filterset = filterset_class(request.GET)
queryset = filterset.filter(queryset)
kwargs['extra_context']['filterset'] = filterset
return object_list(request, queryset, *args, **kwargs)
This is simple and straightforward, but in order to add some tricky pagination, we have to copy entire view and add more code to it.
Instead, we can create decorator like this:
def filtered(view):
def wrapped(request, filterset_class, queryset, *args, **kwargs):
filterset = filterset_class(request.GET)
queryset = filterset.filter(queryset)
kwargs['extra_context']['filterset'] = filterset
return view(request, queryset, *args, **kwargs)
return wrapped
Assuming, that we have similar decorators, sorted
и paginated
, we can easily combine them:
@filtered
@paginated
def technic_list(*args, **kwargs):
# ...
Or even like this, in lisp style:
url(r'^technic/$', filtered(sorted(paginated(object_list))), {
'filterset_class': FilterSet,
# ...
}, name='technic_list'),