"""View decorators for Ajax powered pagination.""" from __future__ import unicode_literals from functools import wraps from el_pagination.settings import ( PAGE_LABEL, TEMPLATE_VARNAME, ) QS_KEY = 'querystring_key' def page_template(template, key=PAGE_LABEL): """Return a view dynamically switching template if the request is Ajax. Decorate a view that takes a *template* and *extra_context* keyword arguments (like generic views). The template is switched to *page_template* if request is ajax and if *querystring_key* variable passed by the request equals to *key*. This allows multiple Ajax paginations in the same page. The name of the page template is given as *page_template* in the extra context. """ def decorator(view): @wraps(view) def decorated(request, *args, **kwargs): # Trust the developer: he wrote ``context.update(extra_context)`` # in his view. extra_context = kwargs.setdefault('extra_context', {}) extra_context['page_template'] = template # Switch the template when the request is Ajax. querystring_key = request.GET.get(QS_KEY, request.POST.get(QS_KEY, PAGE_LABEL)) if request.is_ajax() and querystring_key == key: kwargs[TEMPLATE_VARNAME] = template return view(request, *args, **kwargs) return decorated return decorator def _get_template(querystring_key, mapping): """Return the template corresponding to the given ``querystring_key``.""" default = None try: template_and_keys = mapping.items() except AttributeError: template_and_keys = mapping for template, key in template_and_keys: if key is None: key = PAGE_LABEL default = template if key == querystring_key: return template return default def page_templates(mapping): """Like the *page_template* decorator but manage multiple paginations. You can map multiple templates to *querystring_keys* using the *mapping* dict, e.g.:: @page_templates({ 'page_contents1.html': None, 'page_contents2.html': 'go_to_page', }) def myview(request): ... When the value of the dict is None then the default *querystring_key* (defined in settings) is used. You can use this decorator instead of chaining multiple *page_template* calls. """ def decorator(view): @wraps(view) def decorated(request, *args, **kwargs): # Trust the developer: he wrote ``context.update(extra_context)`` # in his view. extra_context = kwargs.setdefault('extra_context', {}) querystring_key = request.GET.get(QS_KEY, request.POST.get(QS_KEY, PAGE_LABEL)) template = _get_template(querystring_key, mapping) extra_context['page_template'] = template # Switch the template when the request is Ajax. if request.is_ajax() and template: kwargs[TEMPLATE_VARNAME] = template return view(request, *args, **kwargs) return decorated return decorator