Cheng
Cheng

Reputation: 17894

Better ways to handle dynamically generated forms in Django

I have a form that allow users to log their activities. To make it simple, let's say I only have two fields that I want a user to fill out.

During a day, a user can fill out multiple time + action pairs. I used javascript on the front end to allow users to add these pairs as they wish.

Thus, I do not know how many pairs there will be beforehand. And thus, I cannot create a predefined ModelForm for it.

To deal with this issue, I labeled each Time and Action field with a unique name. So when I receive a POST request, I geta list like this inside the request.POST dictionary:

Then, I subtract each pair out of the dictionary and put them into a ModelForm for validation and save to the database.

class TimeActionModel(Model):
    time = DateField()
    action = CharField(max_length=100)

class TimeActionForm(ModelForm):
    class Meta:
        model = TimeActionModel

class TimeActionView(View):
    def post(self, request, *args, **kwargs):
        self._subtract_and_save(request)

    def _subtract_and_save(request):
        #loop through the request.POST dictionary
            #pull out each pair
            #stuff each one into a ModelForm object
            if form.is_valid():
                form.save()

Here is my quesiton:

Thank you!

Upvotes: 4

Views: 170

Answers (1)

Wtower
Wtower

Reputation: 19902

There is a concept in Django called formset:

A formset is a layer of abstraction to work with multiple forms on the same page. It can be best compared to a data grid.

The Django way would be to use Model formsets:

Like regular formsets, Django provides a couple of enhanced formset classes that make it easy to work with Django models.

Therefore you could create a model formset for your TimeActionModel as such:

from django.forms.models import modelformset_factory

TimeActionFormset = modelformset_factory(TimeActionModel)

You can read more on that in the documentation. It has extensive use cases and examples to cover your case.

UPDATE: The extras parameter of the formset is not quite important. You can easily manipulate the number of extra forms in your formset with a bit of javascript. There are also contrib packages for that such as django-dynamic-formset.

UPDATE2: The name of the fields depends on the prefix used too, which I recommend it in case of many different forms/formsets in a single page, but you can easily deduce it looking at a default form that Django renders.

Also please take not not to forget in your template to include {{ my_formset.management_form }} and {{ my_formsets_form.id }}!

Upvotes: 4

Related Questions