Skip to content

Instantly share code, notes, and snippets.

@OEP
Created August 5, 2013 19:59
Show Gist options
  • Save OEP/6159054 to your computer and use it in GitHub Desktop.
Save OEP/6159054 to your computer and use it in GitHub Desktop.
Extensible Django view decorator for confirming things before doing them.
"""
Extensible confirmation decorator.
Simply decorate a view with @confirmation_required and a generic "check the
box" confirmation will show up.
By default the decorator passes the variables "title", "question", "prompt",
"form" and "error" to the template. Additional variables and overrides may be
specifies by passing a dict as the context parameter.
You may wish to do advanced stuff like fetching things from the database based
on which view was triggered. To do this, you'll have to provide processors for
the template arguments. A processor will be passed the template parameter in
the context as the first argument, and the arguments to the view as *args and
**kwargs. Here's an example for clarity:
def process_title(title, *args, **kwargs):
pk = kwargs['pk']
person = Person.objects.get(pk=pk)
return title.format(name=person.first_name)
@confirmation_required(context={"title":"Really delete {name}?"},
processors={title:process_title})
def delete_person(request, pk):
Person.objects.delete(pk=pk)
"""
__all__ = ["confirmation_required"]
from django.utils.translation import ugettext_lazy as _
from django.template import RequestContext
from django.shortcuts import render_to_response
from django import forms
from functools import wraps, partial
class CheckboxChallengeForm(forms.Form):
"""Simple checkbox form."""
confirm = forms.BooleanField()
##: Default template to use for confirm action
DEFAULT_TEMPLATE = "confirmations/default.html"
##: Default context to be passed to template.
DEFAULT_CONTEXT = {
"title": _("Confirmation Required"),
"question": _("Are you sure you want to do that?"),
"form": CheckboxChallengeForm(),
"error": _("Confirm your action."),
}
##: Identity function for text processors.
DEFAULT_PROCESSOR = lambda x, *args, **kw: x
##: Challenge function suitable for making sure the checkbox is checked.
DEFAULT_CHALLENGE = lambda x, *args, **kw: x == "on"
##: Processor mappings
DEFAULT_PROCESSORS = {
}
def confirmation_required(fn=None,
parameter_name="confirm",
context=DEFAULT_CONTEXT,
processors=DEFAULT_PROCESSORS,
challenge=DEFAULT_CHALLENGE,
template=DEFAULT_TEMPLATE):
"""
Decorator which requires user to check a box before the view is served.
This is an extensible decorator which can serve as a basis for a variety of
purposes.
Arguments:
parameter_name: the GET parameter name to check
context: the context to pass to the template
processors: a dict of callables to help process the context
challenge: a challenge function
template: the template to render to
"""
if fn == None:
return partial(confirmation_required,
parameter_name=parameter_name,
context=context,
processors=processors,
challenge=challenge,
template=template)
@wraps(fn)
def decorator(request, *args, **kwargs):
response = request.GET.get(parameter_name)
if challenge(response, *args, **kwargs):
return fn(request, *args, **kwargs)
template_context = dict(DEFAULT_CONTEXT)
template_context.update(context)
for name, processor in processors.items():
value = template_context.get(name)
template_context[name] = processor(value, *args, **kwargs)
return render_to_response(template, template_context,
context_instance=RequestContext(request))
return decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment