1 | """ |
---|
2 | Django class based views for using more than one Form or ModelForm in a single view. |
---|
3 | """ |
---|
4 | from django.http import HttpResponseRedirect |
---|
5 | from django.shortcuts import render |
---|
6 | from django.views.generic import FormView |
---|
7 | |
---|
8 | |
---|
9 | class MultiFormView(FormView): |
---|
10 | """ |
---|
11 | View to handle multiple form classes. |
---|
12 | """ |
---|
13 | form_classes = {} |
---|
14 | |
---|
15 | def are_forms_valid(self, forms): |
---|
16 | """ |
---|
17 | Check if all forms defined in `form_classes` are valid. |
---|
18 | """ |
---|
19 | for form in forms.values(): |
---|
20 | if not form.is_valid(): |
---|
21 | return False |
---|
22 | return True |
---|
23 | |
---|
24 | def forms_valid(self, forms): #pylint: disable=unused-argument |
---|
25 | """ |
---|
26 | Redirects to get_success_url(). |
---|
27 | """ |
---|
28 | return HttpResponseRedirect(self.get_success_url()) |
---|
29 | |
---|
30 | def forms_invalid(self, forms): |
---|
31 | """ |
---|
32 | Renders a response containing the form errors. |
---|
33 | """ |
---|
34 | context = self.get_context_data(forms=forms) |
---|
35 | return render(self.request, self.template_name, context) |
---|
36 | |
---|
37 | def get(self, request, **kwargs): |
---|
38 | """ |
---|
39 | Render the forms. |
---|
40 | """ |
---|
41 | context = self.get_context_data() |
---|
42 | return render(request, self.template_name, context=context) |
---|
43 | |
---|
44 | def get_context_data(self, **kwargs): |
---|
45 | """ |
---|
46 | Add forms into the context dictionary. |
---|
47 | """ |
---|
48 | context = {} |
---|
49 | if 'forms' not in kwargs: |
---|
50 | context['forms'] = self.get_forms() |
---|
51 | else: |
---|
52 | context['forms'] = kwargs['forms'] |
---|
53 | return context |
---|
54 | |
---|
55 | def get_forms(self): |
---|
56 | """ |
---|
57 | Initializes the forms defined in `form_classes` with initial data from `get_initial()` and |
---|
58 | kwargs from get_form_kwargs(). |
---|
59 | """ |
---|
60 | forms = {} |
---|
61 | initial = self.get_initial() |
---|
62 | form_kwargs = self.get_form_kwargs() |
---|
63 | for key, form_class in self.form_classes.items(): |
---|
64 | forms[key] = form_class(initial=initial[key], **form_kwargs) |
---|
65 | return forms |
---|
66 | |
---|
67 | def get_form_kwargs(self): |
---|
68 | """ |
---|
69 | Build the keyword arguments required to instantiate the form. |
---|
70 | """ |
---|
71 | kwargs = {} |
---|
72 | if self.request.method in ('POST', 'PUT'): |
---|
73 | kwargs.update({ |
---|
74 | 'data': self.request.POST, |
---|
75 | 'files': self.request.FILES, |
---|
76 | }) |
---|
77 | return kwargs |
---|
78 | |
---|
79 | def get_initial(self): |
---|
80 | """ |
---|
81 | Returns a copy of `initial` with empty initial data dictionaries for each form. |
---|
82 | """ |
---|
83 | initial = super(MultiFormView, self).get_initial() |
---|
84 | for key in self.form_classes.keys(): |
---|
85 | initial[key] = {} |
---|
86 | return initial |
---|
87 | |
---|
88 | def post(self, request, **kwargs): |
---|
89 | """ |
---|
90 | Uses `are_forms_valid()` to call either `forms_valid()` or * `forms_invalid()`. |
---|
91 | """ |
---|
92 | forms = self.get_forms() |
---|
93 | if self.are_forms_valid(forms): |
---|
94 | return self.forms_valid(forms) |
---|
95 | else: |
---|
96 | return self.forms_invalid(forms) |
---|
97 | |
---|
98 | |
---|
99 | class MultiModelFormView(MultiFormView): |
---|
100 | """ |
---|
101 | View to handle multiple model form classes. |
---|
102 | """ |
---|
103 | |
---|
104 | def forms_valid(self, forms): |
---|
105 | """ |
---|
106 | Calls `save()` on each form. |
---|
107 | """ |
---|
108 | for form in forms.values(): |
---|
109 | form.save() |
---|
110 | return super(MultiModelFormView, self).forms_valid(forms) |
---|
111 | |
---|
112 | def get_forms(self): |
---|
113 | """ |
---|
114 | Initializes the forms defined in `form_classes` with initial data from `get_initial()`, |
---|
115 | kwargs from get_form_kwargs() and form instance object from `get_objects()`. |
---|
116 | """ |
---|
117 | forms = {} |
---|
118 | objects = self.get_objects() |
---|
119 | initial = self.get_initial() |
---|
120 | form_kwargs = self.get_form_kwargs() |
---|
121 | for key, form_class in self.form_classes.items(): |
---|
122 | forms[key] = form_class(instance=objects[key], initial=initial[key], **form_kwargs) |
---|
123 | return forms |
---|
124 | |
---|
125 | def get_objects(self): |
---|
126 | """ |
---|
127 | Returns dictionary with the instance objects for each form. Keys should match the |
---|
128 | corresponding form. |
---|
129 | """ |
---|
130 | objects = {} |
---|
131 | for key in self.form_classes.keys(): |
---|
132 | objects[key] = None |
---|
133 | return objects |
---|