Kiet Tran
Kiet Tran

Reputation: 1538

Django unexpected keyword argument when creating form

Motivation

I'm currently creating a to-do-list app in django for practice. What I'm trying to do now is to give the "user" the option to submit multiple to-do items at once. To do so, I display the form multiple times and then retrieve the items from each form individually.

Attempt & Error

Here's the form in question:

class AddItemForm(forms.Form):
    name = forms.CharField(max_length=60, label='Item Name')
    priority = forms.IntegerField(required=False,
            widget=forms.Select(choices=Item.PRIORITY))
    due_date = forms.DateTimeField(required=False, label='Due Date')

However, when I try to create a form using keyword arguments (the lines of interest are in the for loop):

def add_item(request):
    if request.method == 'POST':
        r = request.POST
        names = r.getlist('name')
        priorities = r.getlist('priority')
        due_dates = r.getlist('due_date')
        for i in xrange(len(names)):
            form = AddItemForm(
                       name=names[i],
                       priority=priorities[i],
                       due_date=due_dates[i],
                   )
            if form.is_valid():
                item = form.cleaned_data
                Item.objects.create(**item) 
        return HttpResponseRedirect('/todo')

    form = AddItemForm()
    try:
        num_items = xrange(int(request.GET.get('n', 1)))
    except ValueError:
        num_items = xrange(1)
    return render(request, 'add_item.html', 
            {'form': form, 'num_items': num_items})

I get the following error message:

Exception Type: TypeError
Exception Value:    
__init__() got an unexpected keyword argument 'priority'

I don't understand what's going on since I do have priority as a field in AddItemForm.

HTML

Here's the template html if it helps:

<!DOCTYPE html>
<html>
  <head> <title>Add item</title> </head>
  <body>
    <form method="post">{% csrf_token %}
      {% for i in num_items %}
        <div>{{ form }}</div>
      {% endfor %}
      <input type="submit">
    </form>

    <br><br>
    <form action="/todo" method="get">
      <input type="submit" value="Go back to To-Do List">
    </form>
  </body>
</html>

Upvotes: 0

Views: 4251

Answers (2)

sangnoir
sangnoir

Reputation: 1

Django the form.init() accepts an 'initial' keyword argument, you could have set the initial values of the form in the following way:

form = AddItemForm(initial = {
                      'name':names[i],
                      'priority':priorities[i],
                      'due_date':due_dates[i],
                   }
               )

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599956

Well, that's not how forms work. You're not supposed to process the POST arguments first, and you can't pass data for individual fields as arguments like that. You're simply supposed to pass request.POST into the form instantiation as-is.

The way to do a set of multiple identical forms is to use a formset. You can then pass the POST data straight into the formset instantiation, and get validated forms out.

Note that since your form is being used to create model instances, you may want to consider using a modelform (and a model formset, on the same page).

Upvotes: 1

Related Questions