Code


Version 16 (modified by Boffbowsh, 9 years ago) (diff)

Comment on the implemented idea for a function

Shortcut syntax ideas

The Django view system is completely flexible and decoupled from the template system, but that flexibility leads to repetitive code when all you want to do is use Django templates. Let's add a "shortcut" syntax to make it super quick for people to write views that use the Django templates.

This page collects ideas on how shortcut syntax would work.

Example

Each example on this page does the equivalent of this:

from django.core.template import Context
from django.core import template_loader
from django.utils.httpwrappers import HttpResponse

def prime_index(request):
    t = template_loader.get_template('primes/index')
    c = Context({
        'title': 'Page Title',
        'primes': [2, 3, 5, 7],
        'header': 'The first 4 primes',
    })
    return HttpResponse(t.render(c))

Idea 1: Decorator

from django.views.decorators.shortcuts import page

@page('primes/index', title='Page Title')      # @page(template_name, **default_context)
def prime_index(request):
    yield {"primes": [2, 3, 5, 7]}
    yield {"header": 'The first 4 primes'}

I think this is brilliant, but with a couple of hangups. Firstly, I think returning a single dictionary would make more sense (in most cases) than yielding - although I have no preblem with yield being supported as an alternative. Secondly, why yield single key dictionaries instead of tuple pairs? - SimonWillison

from django.views.decorators.shortcuts import page

# also:

@page('primes/index', title='Page Title')      # @page(template_name, **default_context)
def prime_index(request):
    primes = [2,3,5,7]
    header = "The first 4 primes"
    yield locals()

I was merely trying to show that you can yield sequentially, and it would add to a single dict. You could just as easily yield a single dictionary. But I've found that sometimes it is nice to be able to yield items at different parts of the function. Also, one can "yield locals()", which can be fun. I've added it above - Brantley

Idea 2: Class

from django.views.templated import TemplatedPage

class PrimeIndex(TemplatedPage):
    def get_context(self, request):
        return {'title': 'Page Title', 'primes': [2, 3, 5, 7], 'header': 'The first 4 primes:'}
prime_index = PrimeIndex('primes/index')

Idea 3: Function

from django.core.extensions import load_and_render

def index(self, request):
     return load_and_render('index', 'title': 'Page Title', 'primes': [2, 3, 5, 7], 'header': 'The first 4 primes:')

I think specifying HttpResponse outside of the function is a better idea: return HttpResponse(load_and_render('index', 'title': 'Page Title', 'primes': [2, 3, 5, 7], 'header': 'The first 4 primes:')) I'll be using the templating system for a LOT more than just HTTP (system configs etc). Maybe have load_and_respond(), load_and_return()?

Idea 4: Simplified decorator

from django.views.decorators.shortcuts import use_template

@use_template('primes/index')
def prime_index(request):
    return {
        'title': 'Page Title',
        'primes': [2, 3, 5, 7],
        'header': 'The first 4 primes'
    }

Idea 5: Class plus decorator

from django.views.decorators.shortcuts import use_template

class AClass(BaseClass):
    #class level attributes here (e.g. for the menu generation - see below)

    @use_template('primes/index')
    def prime_index(request):
        return {
            'title': 'Page Title',
            'primes': [2, 3, 5, 7],
            'header': 'The first 4 primes'
        }

If i dynamically build a menu, etc. I would like to be able to define that at the class level so that I don't have to repeat myself in every method, or repeat myself decorating every method. I'm kind of new to python and am not familiar with all its capabilities so my example may not be the best.

Implementations

Idea 1

This satisfies the complicated and simplistic decorator, return or yield. Also, you can now change the template or context used, by yielding them, e.g. "yield {'template': 'primes/index'}".

It goes in django.views.decorators.shortcuts:

def page(template=None, context=None, **decorator_args):
    def _wrapper(fn):
        def _innerWrapper(request, **args):
            context_dict = decorator_args.copy()
            g = fn(request, **args)
            if not hasattr(g, 'next'):  #Is this a generator?  Otherwise make her a tuple!
                g = (g,)
            for i in g:
                if isinstance(i, httpwrappers.HttpResponse):
                    return i
                if type(i) == type(()):
                    context_dict[i[0]] = i[1]
                else:
                    context_dict.update(i)
            template_name = context_dict.get("template", template)
            context_instance = context_dict.get("context", context)
            return load_and_render(template_name, context_dict, context_instance)
            
        return _innerWrapper
    return _wrapper

Idea 2

Implementation

This goes in django.views.templated:

class TemplatedPage:
    def __init__(self, template_name):
        self.template_name = template_name

    def __call__(self, *args, **kwargs):
        t = template_loader.get_template(self.template_name)
        c = Context(self.get_context(*args, **kwargs))
        return HttpResponse(t.render(c))

Idea 3

Implementation

This goes in django.core.extensions:

def load_and_render(template_name, dictionary, context=None):
    context = context or Context
    t = template_loader.get_template(template_name)
    c = context(dictionary)
    return HttpResponse(t.render(c))