[bf47591] | 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 |
---|