My Django app uses Django Suit as a tool to theme the admin app of Django. One of the things Suit can do is append and prepend elements to form widgets like:
class PropertyForm(ModelForm):
class Meta:
model = Property
widgets = {
'amount': EnclosedInput(prepend = "GBP"),
}
The effect is:
Although this is a nice feature it would be more useful if I could add it dynamically like (in pseudo code):
'amount': EnclosedInput(prepend = my_model_instance.currency)
I tried to override the form's init like so:
class PropertyForm(ModelForm):
def __init__(self, *args, **kwargs):
inst = kwargs["instance"]
self._meta.widgets["amount"] = EnclosedInput(prepend = inst.currency)
super(PropertyForm, self).__init__(*args, **kwargs)
Strangely that only works when I put a breakpoint in the init method. It looks like there's some timing issue involved.
So my question is what would be the best way (if one at all available) to implement this?
A formset is a collection of Django Forms. Each formset has a management form which is used to manage the collection of forms contained in it. Formset stores data like the total number of forms, the initial number of forms and the maximum number of forms in a management form.
But Django doesn’t easily let us edit the form for good designs. Here, we will see one of the ways to customize Django forms, So they will look according to our wish on our HTML page. Basically we will check the methods to include our own custom css, classes, or id to individual fields in forms.
With django-forms-dynamic, we can improve on this approach. We need to do two things: Add the DynamicFormMixin to your form class (before forms.Form ). Wrap any field that needs dynamic behaviour in a DynamicField. The first argument to the DynamicField constructor is the field class that you are wrapping (eg forms.ModelChoiceField ).
The standard way to change a Django form's fields at runtime is override the form's __init__ method, pass in any values you need from the view, and poke around in self.fields: This works, but it doesn't scale very well to more complex requirements.
The problem is with:
self._meta.widgets["amount"] = EnclosedInput(prepend = inst.currency)
It turns out _meta
is being cached. When I change the above line to (which also a nicer solution as _meta is probably private):
self.fields['amount'].widget = EnclosedInput(prepend = inst.currency)
...it works flawlessly
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With