122 lines
4.1 KiB
Python
122 lines
4.1 KiB
Python
from django.contrib.auth.mixins import PermissionRequiredMixin
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
from django.http import HttpResponseRedirect
|
|
from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
|
|
|
|
|
|
class StaffRequiredMixin(PermissionRequiredMixin):
|
|
permission_required = "bds.is_team"
|
|
|
|
|
|
class MultipleFormMixin(ContextMixin):
|
|
"""Mixin pour gérer plusieurs formulaires dans la même vue.
|
|
Le fonctionnement est relativement identique à celui de
|
|
FormMixin, dont la documentation est disponible ici :
|
|
https://docs.djangoproject.com/en/3.0/ref/class-based-views/mixins-editing/
|
|
|
|
Les principales différences sont :
|
|
- au lieu de form_class, il faut donner comme attribut un dict de la forme
|
|
{<form_name>: <form_class>}, avec tous les formulaires à instancier. On
|
|
peut aussi redéfinir `get_form_classes`
|
|
|
|
- les données initiales se récupèrent pour chaque form via l'attribut
|
|
`<form_name>_initial` ou la fonction `get_<form_name>_initial`. De même,
|
|
si certaines forms sont des `ModelForm`s, on peut définir la fonction
|
|
`get_<form_name>_instance`.
|
|
|
|
- chaque form a un préfixe rajouté, par défaut <form_name>, mais qui peut
|
|
être customisé via `prefixes` ou `get_prefixes`.
|
|
"""
|
|
|
|
form_classes = {}
|
|
prefixes = {}
|
|
initial = {}
|
|
|
|
success_url = None
|
|
|
|
def get_form_classes(self):
|
|
return self.form_classes
|
|
|
|
def get_initial(self, form_name):
|
|
initial_attr = "%s_initial" % form_name
|
|
|
|
initial_method = "get_%s_initial" % form_name
|
|
initial_method = getattr(self, initial_method, None)
|
|
|
|
if hasattr(self, initial_attr):
|
|
return getattr(self, initial_attr)
|
|
elif callable(initial_method):
|
|
return initial_method()
|
|
else:
|
|
return self.initial.copy()
|
|
|
|
def get_prefix(self, form_name):
|
|
return self.prefixes.get(form_name, form_name)
|
|
|
|
def get_instance(self, form_name):
|
|
# Au cas où certaines des forms soient des ModelForms
|
|
instance_method = "get_%s_instance" % form_name
|
|
instance_method = getattr(self, instance_method, None)
|
|
|
|
if callable(instance_method):
|
|
return instance_method()
|
|
else:
|
|
return None
|
|
|
|
def get_form_kwargs(self, form_name):
|
|
kwargs = {
|
|
"initial": self.get_initial(form_name),
|
|
"prefix": self.get_prefix(form_name),
|
|
"instance": self.get_instance(form_name),
|
|
}
|
|
|
|
if self.request.method in ("POST", "PUT"):
|
|
kwargs.update({"data": self.request.POST, "files": self.request.FILES})
|
|
|
|
return kwargs
|
|
|
|
def get_forms(self):
|
|
form_classes = self.get_form_classes()
|
|
return {
|
|
form_name: form_class(**self.get_form_kwargs(form_name))
|
|
for form_name, form_class in form_classes.items()
|
|
}
|
|
|
|
def get_success_url(self):
|
|
if not self.success_url:
|
|
raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.")
|
|
return str(self.success_url)
|
|
|
|
def form_valid(self, forms):
|
|
# on garde le nom form_valid pour l'interface avec SuccessMessageMixin
|
|
return HttpResponseRedirect(self.get_success_url())
|
|
|
|
def form_invalid(self, forms):
|
|
"""If the form is invalid, render the invalid form."""
|
|
return self.render_to_response(self.get_context_data(forms=forms))
|
|
|
|
|
|
class ProcessMultipleFormView(View):
|
|
"""Équivalent de `ProcessFormView` pour plusieurs forms.
|
|
Note : il faut que *tous* les formulaires soient valides pour
|
|
qu'ils soient sauvegardés !
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
forms = self.get_forms()
|
|
return self.render_to_response(self.get_context_data(forms=forms))
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
forms = self.get_forms()
|
|
if all(form.is_valid() for form in forms.values()):
|
|
return self.form_valid(forms)
|
|
else:
|
|
return self.form_invalid(forms)
|
|
|
|
|
|
class BaseMultipleFormView(MultipleFormMixin, ProcessMultipleFormView):
|
|
pass
|
|
|
|
|
|
class MultipleFormView(TemplateResponseMixin, BaseMultipleFormView):
|
|
pass
|