Django admin Interdependent validation of formsets
i have two inlines in admin models
class AdminModel(admin.ModelAdmin):
...
inlines = [inline1, inline2]
form = AdminModelForm
model =model
class inline1(admin.TabularInline):
form = inline1form
model = inline1model
class inline2(admin.TabularInline):
form = inline2form
model = inline2model
class inline1form(forms.ModelForm):
class Meta:
model = inline1Edge
fields = ("field1",)
class inline2form(forms.ModelForm):
class Meta:
model = inline2Edge
fields = ("field2",)
class AdminModelForm(forms.ModelForm):
....
admin.site.register(model, AdminModel)
now my task is to check if in two inline, if two fields have value (one in inline1 and another in inline2) then show error
i have come with a solution where when creating formsets i am checking if field has vlaue then return answer
ie modified custom method `
class AdminModel(admin.ModelAdmin):
def _create_formsets(self, request, new_object, change):
formsets, inline_instances = super()._create_formsets(request, new_object, change)
if request.method == "POST":
location_formset = None
individual_formset_validated = all([formset.is_valid() for formset in formsets])
if not individual_formset_validated:
return individual_formset_validated
# custom check condition on formsets
if check_fail:
inline1formset.non_form_errors().extend(
["Please select values for only one field, field1 config or field2 config"]
)
return formsets, inline_instances
this is working fine, and adding error in the inline
is there any other pythonic way which can help me solve this task ?
you could refactor your validation logic by using a cleaner approach
from django.core.exceptions import ValidationError
class Inline1Formset(forms.BaseInlineFormSet):
def clean(self):
super().clean()
for form in self.forms:
field1_value = form.cleaned_data.get("field1")
# Store value in the formset or raise ValidationError here if needed.
class Inline2Formset(forms.BaseInlineFormSet):
def clean(self):
super().clean()
for form in self.forms:
field2_value = form.cleaned_data.get("field2")
# Store value in the formset or raise ValidationError here if needed.
Use the custom formset to enforce the validation across both inlines.
class AdminModel(admin.ModelAdmin):
inlines = [Inline1, Inline2]
form = AdminModelForm
def _create_formsets(self, request, obj, change):
formsets, inline_instances = super()._create_formsets(request, obj, change)
if request.method == "POST":
formset_valid = all([formset.is_valid() for formset in formsets])
if not formset_valid:
return formsets, inline_instances
# Extract the relevant data for cross-formset validation
inline1_formset = [fs for fs in formsets if isinstance(fs, Inline1Formset)][0]
inline2_formset = [fs for fs in formsets if isinstance(fs, Inline2Formset)][0]
field1_value = any(form.cleaned_data.get("field1") for form in inline1_formset)
field2_value = any(form.cleaned_data.get("field2") for form in inline2_formset)
if field1_value and field2_value:
inline1_formset.non_form_errors().append(
"Please select values for only one field: field1 or field2."
)
return formsets, inline_instances