Learn Django

Update the Form

With your newfound knowledge of classes, inheritance, and mixins, it's time to update the subscriber form to include a section that collects the first name, last name, and address of the soon to be paying customer.

Our goal is to have one form that contains fields from two different models. While Django has a simple method to base a form off a model, it doesn't support having a form based on two models. That's ok because we can simply use a mixin.

As you can see below, there are two form classes defined. The second one, the SubscriberForm, is the one that will ultimately be rendered in the template. To ensure it contains the right fields, we're basing it on the custom AddressMixin we created, and Django's built-in UserCreationForm.

Open the /.../crmeasy/crmapp/subscribers/forms.py file in your IDE. Update it so that it looks like the following. There are several big changes in the file below so be sure to update it correctly.

New or modified lines are highlighted in yellow.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from django import forms
from django.contrib.auth.forms import UserCreationForm

from .models import Subscriber  


class AddressMixin(forms.ModelForm):
    class Meta:
        model = Subscriber
        fields = ('address_one', 'address_two', 'city', 'state',)
        widgets = {
            'address_one': forms.TextInput(attrs={'class':'form-control'}),
            'address_two': forms.TextInput(attrs={'class':'form-control'}),
            'city': forms.TextInput(attrs={'class':'form-control'}),
            'state': forms.TextInput(attrs={'class':'form-control'}),
        }  


class SubscriberForm(AddressMixin, UserCreationForm):
    first_name = forms.CharField(
        required=True, widget=forms.TextInput(attrs={'class':'form-control'})
    )
    last_name = forms.CharField(
        required=True, widget=forms.TextInput(attrs={'class':'form-control'})
    )
    email = forms.EmailField(
        required=True, widget=forms.TextInput(attrs={'class':'form-control'})
    )
    username = forms.CharField(
        widget=forms.TextInput(attrs={'class':'form-control'})
    )
    password1 = forms.CharField(
        widget=forms.TextInput(attrs={'class':'form-control', 'type':'password'})
    )
    password2 = forms.CharField(
        widget=forms.TextInput(attrs={'class':'form-control', 'type':'password'})
    )

Code Review (only new or changed code is reviewed)

Line 4: Imports the Subscriber model which is required in the form definition.

Line 6: This line starts the form definition. It specifies that this will be a Python class, the class name will be AddressMixin, and that it subclasses forms.ModelForm. The ModelForm is used when you want a form to be based on a model; in this case it will be based on the Subscriber model.

Line 7: This sets an inner class that allows for the definition of metadata. This is a requirement for forms based on ModelForm.

Line 8: The 'model = Subscriber' tells Django that this form is based on the Subscriber model.

Line 9: Because this form is based on a model, you can use the fields attribute to define which fields are shown in the form and which aren't. Here we specify the fields that are to be shown.

Line 10: This sets the widgets attribute. Widgets are used to modify form elements. In this example, all of the fields are set to TextInput, which will render a <input> HTML element. Widgets can also be used to set attribute values of the HTML elements. In this code we're setting the class value to be 'form-control'.

Line 17: This is similar to the code that was already in your file, with one change. This class now has two inheritances; one from AddressMixin, and the other from UserCreationForm. This extends our original form so that it includes the fields from the AddressMixin class.

Commit Changes

Execute these commands to commit your changes in Git.

1
2
3
4
5
# add files
(venv)$ git add .

# commit files
(venv)$ git commit -m "updated the form"

Track your progress with a free account