(This is all pseudocode and is not guaranteed to run.)
I am trying to make a "django admin form generator function" that outputs a django form. The current use case is to write reusable code that disallows admins from leaving a field empty, without also marking these fields as non-nullable.
So suppose there exists a model Foo
, in which are some nullable fields:
class Foo(Model):
field1 = FloatField(null=True, blank=True, default=0.0)
field2 = FloatField(null=True, blank=True, default=0.0)
field3 = FloatField(null=True, blank=True, default=0.0)
and corresponding FooAdmin
and FooForm
, such that these fields cannot be made None
from the admin.
class FooAdmin(ModelAdmin):
class FooForm(ModelForm):
class Meta(object):
model = Foo
fields = '__all__'
def _ensure_no_blanks(self, field):
value = self.cleaned_data.get(field)
if value is None:
raise forms.ValidationError(_('This field is required.'))
return value
# repeat methods for every field to check
def clean_field1(self):
return self._ensure_no_blanks('field1')
def clean_field2(self):
return self._ensure_no_blanks('field2')
def clean_field3(self):
return self._ensure_no_blanks('field3')
form = FooForm
As you can see, having to write clean_field1
, clean_field2
, and clean_field_n
are repetitive and error-prone, so I write this helper function to generate model admins:
import functools
from django import forms
def form_with_fields(model_class, required_fields):
class CustomForm(forms.ModelForm):
class Meta(object):
model = model_class
fields = '__all__'
def ensure_no_blanks(self, field):
print field
value = self.cleaned_data.get(field)
if value is None:
raise forms.ValidationError('This field is required.')
return value
# make a clean_bar method for every field that I need to check for None
for field_name in required_fields:
handler = functools.partial(CustomForm.ensure_no_blanks, field=field_name)
setattr(CustomForm, 'clean_' + field_name, lambda self: handler(self))
return CustomForm
class CustomAdmin(ModelAdmin):
form = form_with_fields(Foo, ['field1', 'field2', 'field3'])
However, if you run such an admin, and if you do try to save the Foo
model through the admin, you will see print field
printing field3
three times in the terminal (i.e. all partial
s are retaining the last-run value).
Other attempts include overriding CustomForm
's __getattr__()
, and wrapping CustomForm
in a type('Form', (CustomForm,), ...
, which also exhibit the same behavior.
Is there a dry way to achieve this?