When you can't return a response object, throw it

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""
Motivation
==========
There are cases when rendering had already started, but you have to return Your response nevertheless. A good example is when you have a django-cms plugin and a form in it. You want to redirect after the form was processed, but normally you can't do it.

More information here:
https://github.com/divio/django-cms/issues/79
http://groups.google.com/group/django-cms/browse_thread/thread/79ab6080c80bbcb5?pli=1

Usage
=====
1) Add ForceRedirectsMiddleware to MIDDLEWARE_CLASSES in your settings.py
2) throw ForceResponse(HttpResponseRedirect(reverse('your_view_name'))) whenever you want.


Code example (working cms plugin):
==================================
from cv.utils import ForceResponse

class CVPlugin(CMSPluginBase):
    def render(self, context, instance, placeholder):
        request = context['request']
        if request.method == 'POST':
            cv_form = CVForm(request.POST, request.FILES)
        else:
            cv_form = CVForm()

        if not cv_form.is_valid():
            context.update({ 'form' : cv_form })
            return context

        # Saving CV
        cv = cv_form.save(commit=False)
        code = cv.gen_code()
        cv.save()
            
        raise ForceResponse(HttpResponseRedirect(reverse('dashboard',
            kwargs={'code': cv.code})))

plugin_pool.register_plugin(CVPlugin)
"""

class ForceResponse(Exception):
    def __init__(self, response):
        self.response = response

class ForceResponseMiddleware:
    def process_exception(self, request, e):
        """Because django plugins cannot throw raw response
        (redirect is required to user dashboard after form is submitted),
        a solution is to raise an exception, catch it with middleware and
        react.

        This middleware checks for ForceResponse exception and returns it's
        response object.

        In reality, ForceResponse is caught as TemplateSyntaxtError in cms
        plugin. So we have to extract ForceResponse from it.

        Instance of TemplateSyntaxError has exc_info field where it has the
        original exception. exc_info[1] is the exception instance.
        """
        from django.template import TemplateSyntaxError
        if isinstance(e, TemplateSyntaxError) and getattr(e, 'exc_info', 0):
            try:
                e = e.exc_info[1]
            except: # Not iterable or IndexError
                raise e # as if nothing had happened
        if isinstance(e, ForceResponse):
            return e.response

More like this

  1. Effective content caching for mass-load site using redirect feature by nnseva 2 years, 9 months ago
  2. Simple FastCGI authorizer view by cme 5 years, 6 months ago
  3. Allow separation of GET and POST implementations by agore 1 year, 10 months ago
  4. Workaround Firefox bug 553888 by peroksid 3 years, 1 month ago
  5. Flow player template for django-cms file plugin by justhamade 4 years, 2 months ago

Comments

mludvig (on April 13, 2012):

This is exactly what I needed for my django-cms form plugin :) Thanks!

#

(Forgotten your password?)