Login

CBV: PreviewMixin

Author:
jannh
Posted:
March 29, 2015
Language:
Python
Version:
1.7
Tags:
django mixin cbv
Score:
0 (after 0 ratings)

PreviewMixin adds a preview page for Django's CBV (FormView, UpdateView, CreateView). After a form has been submitted, it is returned again, optionally in a different template to confirm. If the form is submitted with the same data, the default "form_valid" function is executed.

Features: 1. process_preview - function executed after submitting the form for the first time (default is to do nothing) 2. done - function for the action if the confirm page is sent (defaults to whatever form_valid of the django cbv does) 3. preview_template_name - variable with the name of the template for the confirm page (defaults to taking the same template as for the initial form) 4. new function security_hash to calculate a hash which is added to the confirmation form.

Works kind of like django-formtools, just as a Mixin for the default Django cbv.

 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
71
72
73
74
75
76
from django import forms
from formtools.utils import form_hmac
import copy


class PreviewMixin(object):
    '''
    Mixin for a 2-stage form

    For usage with the default django class-based views (CreateView, UpdateView, FormView)

    Procedure:
    First display a form in a template.
    When submitted, execute process_preview, then redisplay the form.
    If submitted again and the data matches the previous submit, run done.
    Else run process_preview again and redisplay the form once again.
    '''
    stage = 1
    preview_template_name = None

    def get_template_names(self):
        '''
        Depending on the stage, return the appropriate template
        Use the default template of the Django View for the first stage
        If a different template is wanted for the second stage, preview_template_name can be set.
        Otherwise the default template of the Django View is also used for the second stage.
        '''
        if self.stage == 2 and self.preview_template_name is not None:
            return [self.preview_template_name]
        return super(PreviewMixin, self).get_template_names()

    def get_form(self, form_class=None):
        '''
        Add a hash value to each form.
        If stage==1 (first form or previous invalid data), pass 0 as hash value
        '''
        form = super(PreviewMixin, self).get_form(form_class)
        if self.stage == 2:
            form.fields['hash'] = forms.CharField(initial='0', widget=forms.HiddenInput)
        return form
    def form_valid(self, form):
        '''
        Check if form was submitted the first or second time.
        If it is the second time and the hash-value matches, run done()
        Else run process_preview and return the second form.
        Should not be overwritten.
        '''
        if self.security_hash(form) == self.request.POST.get('hash', '0'):
            return self.done(form)
        self.process_preview(form)
        self.stage = 2
        self.request.POST['hash'] = self.security_hash(form)
        form = self.get_form(self.get_form_class())
        return self.render_to_response(self.get_context_data(form=form))

    def security_hash(self, form):
        '''
        Function to return the hash value of the form
        '''
        hash_form = copy.copy(form)
        hash_form.fields.pop('hash', '')
        return form_hmac(hash_form)

    def process_preview(self, form):
        '''
        Function which is run after the form was valid for the first time.
        Does nothing by default.
        '''
        pass

    def done(self, form):
        '''
        Function which is run after the form was submitted the second time if it is valid and the hash values match.
        By default does the same as the corresponding form_valid function of the class-based view it inherits from.
        '''
        return super(PreviewMixin, self).form_valid()

More like this

Comments

Please login first before commenting.