How to create separate Name and Surname inputs as one widget in Django
Today I'll show you a nice little trick that's useful if you want your new users to input their first name and last name separately, so that you know where the separation is. This allows you to say things like "Hello, Mr. Smith" or "Hello, Keanu" on your site, instead of the full name or guessing which part is name and which part is surname (a tricky and not-so-accurate business, for a variety of reasons).
This is what we want our form to look like (taken from Fumana):

The most important thing to notice is that there is only one label for both fields, something that is not easily done with default Django Forms, unless you know how. The trick is to use a MultiWidget. This allows us to combine two TextInput fields into one Form Field, with a shared label. Place this code in a separate widgets.py that you create within your app folder:
class NameSurnameWidget(forms.MultiWidget):
"""
MultiWidget = A widget that is composed of multiple widgets.
This class combines a CharInput and another CharInput for "Name" and "Surname"
"""
def __init__(self, attrs=None):
""" pass all these parameters to their respective widget constructors..."""
_widgets = (TextInput(attrs={'class': 'first_name', 'placeholder': 'First Name'}), TextInput(attrs={'class': 'last_name', 'placeholder': 'Last Name'}))
super(NameSurnameWidget, self).__init__(_widgets, attrs)
def decompress(self, value):
if value:
name, surname = value.name, value.surname
return [name, surname]
return ['', '']
def format_output(self, rendered_widgets):
"""
Given a list of rendered widgets (as strings), it joins them. You can also put in a <br/> or something here, if you choose
Returns a Unicode string representing the HTML for the whole lot.
"""
return u''.join(rendered_widgets)
The comments mostly explain what this code does and how it works. Just one note: In this example, the placeholder text ("First name" and "Last name") is hardcoded into the MultiWidget. You can remove this, parameterize it to make it adapt to the form you use it in, or change it to something else. The placeholder is an HTML5 attribute however, so make sure you support older browsers when you use this (You can do this with jQuery, check this link for more info).
To use the widget is easy, just import it in your forms.py file, and make use of the widget parameter when instantiating the field for the user's full name:
class SimpleRegistrationForm(models.ModelForm):
name = forms.CharField(widget=widgets.NameSurnameWidget(), label="Your Name")
....
Then, in the form's cleaned_data dictionary, under name, you will get a two-element array, like this:
self.cleaned_data.get('name')
> ['name', 'surname']
Use this to test the validity of the input, and post-process the input into the correct Model fields.
If you found this post interesting, you might also like our blog post, Setting the Instance on a Django Model Form Class Based View
