[Fixed]-Django forms dynamic generation and validation

1👍

You can do that by overriding the __init__() method of FooForm.

We override the __init__() method and check if instance argument was passed to the form. If instance was passed, we disable the root and leaf form fields so that it is not displayed in the template.

We will pass instance argument to the form when the request is of type foo/create/4 i.e. leaf_id is not None.

forms.py

class FooForm(ModelForm):    

    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs) # call the 'super()' init method
        instance = getattr(self, 'instance', None) # get the `instance` form attribute 
        if instance and instance.id: # check if form has 'instance' attribute set and 'instance' has an id
            self.fields['root'].widget.attrs['disabled'] = 'disabled' # disable the 'root' form field
            self.fields['leaf'].widget.attrs['disabled'] = 'disabled' # disable the 'leaf' form field

    # custom validation functions here
    ....

    class Meta:
        model = Foo
        fields = '__all__'

In our view, we first check if leaf_id argument was passed to this view. If leaf_id was passed,we retrieve the Foo object having leaf id as the leaf_id. This instance is then passed when initializing a form and is updated when form.save() is called. We will use the instance to populate the form with values as the attributes set on the instance.

If leaf_id is not passed, then we initialize FooForm with data argument.

views.py

def create(request, leaf_id=None):
    # Get the instance if any
    instance = None
     if leaf_id:
        instance = Foo.objects.get(leaf_id=leaf_id) # get the 'Foo' instance from leaf_id

    # POST request handling
    if request.method=='POST':    
        if instance:      
            form = FooForm(data=request.POST, instance=instance) # Populate the form with initial data and supply the 'instance' to be used in 'form.save()'
        else:
            form = FooForm(data=request.POST)

        if form.is_valid():
            new = form.save()
            return redirect('show.html', root_id=new.root.id)

        return render('create_foo.html', 
                  { 'form': form })

    # GET request handling    
    if instance:
        form = FooForm(initial=instance._data, instance=instance) # form will be populated with instance data
    else:
        form = FooForm() # blank form is initialized        
    return render('create_foo.html', 
                  { 'form': form })

Leave a comment