Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically modifying a form widget in Django

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:

enter image description here

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?

like image 276
Roger Avatar asked Mar 13 '13 10:03

Roger


People also ask

What is formset in Django?

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.

How to customize Django forms for good design?

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.

How to create a dynamic form with Django-forms-dynamic?

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 ).

How to change form fields at runtime in Django?

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.


1 Answers

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

like image 70
Roger Avatar answered Sep 20 '22 14:09

Roger