4

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.

  • Time
  • Action

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:

  • time_1: 9:50
  • action_1: wakeup
  • time_2: 11:00
  • aciton_2: workout
  • ...

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:

  • Does this approach look right to you?
  • What's the 'Django way' of dealing with such situation?

Thank you!

Cheng
  • 16,824
  • 23
  • 74
  • 104

1 Answers1

4

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 }}!

Community
  • 1
  • 1
Wtower
  • 18,848
  • 11
  • 103
  • 80
  • Thanks for pointing that out. While reading the formset documentation, it states `formset_factory(ArticleForm, extra=2)` which means you have to define how many sets there will be displayed on the rendered page. But for my situation, I do not know how many TimeAction pairs there will be. Thus, I have no idea what number of extra I should set it to. – Cheng May 26 '15 at 12:58
  • Thanks. I see what you mean. It looks like I need to use javascript to increment the hidden 'form-TOTAL_FORMS' everytime a new form is added. Also, with a newly added form, I need to make sure each input field has a name in the 'form-set_number-field_name' format. Am I right? – Cheng May 26 '15 at 13:27
  • Welcome! Again updated answer and added link http://stackoverflow.com/a/8097617/940098 – Wtower May 26 '15 at 13:37