Code

Opened 4 years ago

Closed 4 years ago

#12329 closed (wontfix)

"template" view decorator, allows to completely isolate views from templates

Reported by: gurunars Owned by: nobody
Component: Uncategorized Version: 1.1
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Well, the key point of this decorator is to let the developer define a template for the view in the following way:

@template
def view_name(request):
    ...

OR

@template("template_name")
def view_name(request):
    ...

In the first case the decorator automatically composes template's name in the following way: "app_name/view_name.html". This is the same name you would use in a "render_to_response" shortcut function.

In the second case you define template's name explicitly. Again use the same name you would use for the "render_to_response" shortcut function.

In both cases the return type can be either a dictionary, an HttpResponse or an HttpResponseHolder. The last one is just an extension to HttpResponse base class - it has just a single additional parameter called "context" (it is a dictionary). The only purpose of HttpResponseHolder is to pass a context dictionary to some other decorators for further processing. What kind of processing? I will give some examples below.

First example is quite trivial. How to pass the "MEDIA_PATH" parameter from "settings.py" to all the templates? In this case it is really simple - use a decorator as the one just below

from django.conf import settings
from .template import *

class media(object):

    def __init__(self, orig_func):
        self.orig_func = orig_func
        #to compose template's name properly
        self.__name__ = self.orig_func.__name__
        self.__module__ = self.orig_func.__module__

    def __call__(self, *args, **kwargs):
        return_val = self.orig_func(*args, **kwargs)
        if isinstance(return_val, HttpResponseHolder):
            return_val.context["MEDIA_URL"] = settings.MEDIA_URL
        elif isinstance(return_val, dict):
            return_val["MEDIA_URL"] = settings.MEDIA_URL
        return return_val

in chain with the "template" decorator

@template()
@media
def view_name(request):
    ...

Second example is little bit more sophisticated but useful. How to pass to the template information about the user that is currently logged in (user object)? Use the following decorator

from .template import * #HttpResponseHolder

class user(object):

    def __init__(self, orig_func):
        self.orig_func = orig_func
        #to compose template's name properly
        self.__name__ = self.orig_func.__name__
        self.__module__ = self.orig_func.__module__

    def __call__(self, request, *args, **kwargs):
        return_val = self.orig_func(request, *args, **kwargs)
        if request.user:
            if isinstance(return_val, HttpResponseHolder):
                return_val.context["user"] = request.user
            elif isinstance(return_val, dict):
                return_val["user"] = request.user
        return return_val

again in chain with the "template" decorator

@template()
@user
def view_name(request):
    ...

Definitely, writing your own decorators requires some skills in Python. But once done they simplify your life a lot.

Attachments (2)

template.py (1.5 KB) - added by gurunars 4 years ago.
The source code of the decorator
template_v2.py (1.6 KB) - added by gurunars 4 years ago.
Modified "template" decorator. Now uses RequestContext instead of standard Context

Download all attachments as: .zip

Change History (3)

Changed 4 years ago by gurunars

The source code of the decorator

Changed 4 years ago by gurunars

Modified "template" decorator. Now uses RequestContext instead of standard Context

comment:1 Changed 4 years ago by russellm

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to wontfix
  • Status changed from new to closed

This has been requested several times, and rejected. I (and others in the core) simply don't see that using decorators in this way makes anything clearer.

The current contract for a view is that it accepts a request, returns a response. If you use a decorator to modify templates, this contract becomes "returns a response, or a response holder, or a dictionary". This isn't an improvement.

An alternate proposal that *does* have some support in the core is the idea of a TemplateResponse - that is, that you can return a response whose template will be lazily evaluated, allowing decorators, middlewares, or view wrappers to modify the template that is used. This means a view can return a template and a context, but the actual template that is used can be modified by something higher up in the chain. For details, see ticket #12815.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.