Skip to content

Instantly share code, notes, and snippets.

@CleitonDeLima
Last active November 24, 2022 15:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CleitonDeLima/b1530b3d45bf1576cedb4056e1aa1df1 to your computer and use it in GitHub Desktop.
Save CleitonDeLima/b1530b3d45bf1576cedb4056e1aa1df1 to your computer and use it in GitHub Desktop.
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