Last active
November 24, 2022 15:35
-
-
Save CleitonDeLima/b1530b3d45bf1576cedb4056e1aa1df1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.forms import BaseInlineFormSet, Media | |
class BaseInlineNestedFormSet(BaseInlineFormSet): | |
""" | |
Classe usada para criar formsets aninhados | |
Example: | |
class NestedFormSet(BaseInlineNestedFormSet): | |
nesteds = { | |
"prefix": FormSet, | |
} | |
nesteds_kwargs = { | |
"prefix": { ...FormSet kwargs... } | |
} | |
""" | |
nesteds = {} | |
nesteds_kwargs = {} | |
def __init__(self, *args, **kwargs): | |
self._non_nested_form_errors = [] | |
super().__init__(*args, **kwargs) | |
def add_fields(self, form, index): | |
super().add_fields(form, index) | |
for prefix_name, formset_class in self.nesteds.items(): | |
prefix = "{0}-{1}-{2}".format( | |
form.prefix, | |
prefix_name, | |
formset_class.get_default_prefix(), | |
) | |
formset_kwargs = { | |
"instance": form.instance, | |
"data": form.data if form.is_bound else None, | |
"files": form.files if form.is_bound else None, | |
"prefix": prefix, | |
**self.nesteds_kwargs.get(prefix_name, {}), | |
} | |
setattr(form, prefix_name, formset_class(**formset_kwargs)) | |
form.nested_formsets = self.nested_formsets | |
def is_valid(self): | |
changed_children = any(f.has_changed() for f in self.nested_formsets) | |
if not self.has_changed() and changed_children: | |
self.min_num = 1 | |
self.validate_min = True | |
result = super().is_valid() | |
if self.is_bound: | |
for formset in self.nested_formsets: | |
result = result and formset.is_valid() | |
return result | |
def save(self, commit=True): | |
result = super().save(commit=commit) | |
for form in self.forms: | |
if not self._should_delete_form(form): | |
for name in self.nesteds.keys(): | |
formset = getattr(form, name) | |
formset.save(commit=commit) | |
return result | |
def total_error_count(self): | |
total = super().total_error_count() | |
for formset in self.nested_formsets: | |
total += formset.total_error_count() | |
return total | |
def non_form_errors(self): | |
errors = super().non_form_errors() | |
if not self._non_nested_form_errors: | |
for formset in self.nested_formsets: | |
self._non_nested_form_errors += formset.non_form_errors() | |
return errors + self._non_nested_form_errors | |
@property | |
def media(self): | |
media = Media() | |
for formset in self.nested_formsets: | |
media = media + formset.media | |
return media + self.empty_form.media | |
@property | |
def nested_formsets(self): | |
for form in self.forms: | |
for name in self.nesteds.keys(): | |
yield getattr(form, name) | |
# example of how to use... | |
DocumentFormSet = forms.inlineformset_factory( | |
Travel, Document, DocumentForm, extra=0, min_num=1, validate_min=True | |
) | |
class TravelFormset(BaseInlineNestedFormSet): | |
nesteds = { | |
"document": DocumentFormSet, | |
} | |
nesteds_kwargs = { | |
"document": { | |
"queryset": Document.objects.order_by("created"), | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment