Dean
Dean

Reputation: 8978

Django Form not rendering

I have the following form in forms.py:

class ContractForm(forms.Form):
    title = forms.CharField()
    start_date = forms.DateField()
    end_date = forms.DateField()
    description = forms.CharField(widget=forms.Textarea)
    client = forms.ModelChoiceField(queryset=Client.objects.all())

    def __init__(self, user, *args, **kwargs):
        super(ContractForm, self).__init__(*args, **kwargs)
        self.fields['client'] = forms.ModelChoiceField(queryset=Client.objects.filter(user=user))
        clients = Client.objects.filter(user = user)
        for client in clients:
            print client   

And in my view the method looks like this:

def addContract(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/contractManagement/login/?next=%s' % request.path)
else:   
    if request.method == 'POST':
        contractForm = ContractForm(request.POST)
        title = request.POST['title']
        start_date = request.POST['start_date']
        end_date = request.POST['end_date']
        description = request.POST['description']
        client = request.POST['client']
        user = request.user
        contract = Contract(title,start_date,end_date,description,client,user)
        contract.save()
        return HttpResponseRedirect('../../accounts/profile/')
    else:
        user = request.user
        print user.username
        contractForm = ContractForm(user)
        return render_to_response('newcontract.html', {'contractForm': contractForm})

But the form won't render in the browser. All that shows up is the submit button. My HTML looks like this:

<html>
<head>
</head>
<body>
{% if contractForm.errors %}
<p style="color: red;">
    Please correct the error{{ contractForm.errors|pluralize }} below.
</p>
{% endif %}
<form method="POST" action="">    
    <table>
        {{ contractForm.as_table }}
    </table> 
    <input type="submit" value="Submit" />
</form> 
 </body>
</html>

So why won't the form render?


EDIT I have got rid of the custom client field requiring the user and it still won't render. I thought this might help. So a form could use this class:

class ContractForm(forms.Form):
    title = forms.CharField()
    start_date = forms.DateField()
    end_date = forms.DateField()
    description = forms.CharField(widget=forms.Textarea)
    client = forms.ModelChoiceField(queryset=Client.objects.all()) 

Upvotes: 3

Views: 2604

Answers (3)

Dean
Dean

Reputation: 8978

Change the name of the forms in the view. It now looks like this

form = ContractForm(user=request.user)

And it works.

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599450

There are quite a few things wrong here, in addition to the QuerySet issue Arnaud points to.

Firstly, when you instantiate the form in response to a GET, you do contractForm = ContractForm(user). But the first parameter to a form instantiation (as you correctly do in the POST) is the posted data - and you haven't altered the form's __init__ signature.

Secondly, in the __init__ itself, you reference a user variable: but you haven't actually got that variable from anywhere. You can't magically reference variables without receiving them from somewhere.

So to fix those errors, you need to change the init method as follows:

def __init__(self, *args, **kwargs):
    user = kwargs.pop('user')
    super(ContractForm, self).__init__(*args, **kwargs)
    self.fields['client'].queryset=Client.objects.filter(user=user)

and instantiate the form in the view like this:

contractForm = ContractForm(user=request.user)

Thirdly, although this is not related to the problem you post, you will never see any errors on this form, because you don't check it is valid in the POST section - you need to check if contractForm.is_valid(), and if not fall through to the final render_to_response (which needs to be unindented one level).

Also, you are ignoring the whole point of having a form, by setting your model direct from request.POST. You should be using the contents of contractForm.cleaned_data to create the Contract instance.

And finally, you should investigate whether a ModelForm would meet your needs better.

Upvotes: 2

Arnaud
Arnaud

Reputation: 1815

The queryset argument to forms.ModelChoiceField should be a queryset. It should read:

self.fields['client'] = forms.ModelChoiceField(queryset=Client.objects.filter(user=user))

And you have to declare it in your form first before overriding it in the __init__() method:

class ContractForm(forms.Form):
    ...
    client = forms.ModelChoiceField(queryset=Client.objects.all())

Upvotes: 2

Related Questions