Doing things with Django forms
By : Shabda Raaj
Forms are one of the best features of Django. (After models, admin, url routing etc :) ). Here is a quick tutorial describing how to do things with Django forms.
- Basic form
Prob. You want to show a form, validate it and display it.
Ans. Create a simple form.
class UserForm(forms.Form):
username = forms.CharField()
joined_on = forms.DateField()
This wil take care that the form is displayed with two text field, and a value for them are filled in, and the second field has correct formatting for a date.
2.
Prob. Create a form which has values populated depending upon a runtime value, eg you might want to show only the values corresponding to the current subdomain.
Ans. Create a form with an custom __init__.
class UserForm(forms.Form):
username = forms.CharField()
plan = forms.ModelChoiceField(queryset = Plan.objects.none())
def __init__(self, subdomain, *args, **kwargs):
self.default_username = default_username
super(UserForm, self).__init__(*args, **kwargs)
self.fields['plan'].queryset = Plan.objects.filter(subdomain = subdomain)
Here in the __init__ we are overriding the default queryset on field plan. Any of the attributes can similarly be overridden.
However the self.fields is populated only after super(UserForm, self).__init__(*args, **kwargs) is called.
3.
Prob. The same form is used in multiple views, and handles the cleaned_data similarly.
Ans. Create a form with a custom .save()
class UserForm(forms.Form):
username = forms.CharField()
def save(self):
data = self.cleaned_data
user = User.objects.create(username = data['username'])
#create a profile
UserProfile.objects.create(user = user, ...some more data...)
You could have called this method anything, but this is generally called save, to maintain similarity with ModelForm
4.
Prob. You need to create a form with fields which have custom validations.
Ans. Create a form with custom clean_fieldname
class UserForm(forms.Form):
username = forms.CharField()
def clean_username(self):
data = self.cleaned_data
try:
User.objects.get(username = data['username'])
except User.DoesNotExist:
return data['username']
raise forms.ValidationError('This username is already taken.')
Here we can validate that the usernames are not repeated.
5.
Prob. You want to create a field which has cross field validations.
Ans. Create a field with a .clean
class UserForm(forms.Form):
username = forms.CharField()
password1 = forms.PasswordField()
password2 = forms.PasswordField()
def clean(self):
data = self.cleaned_data
if "password1" in data and "password2" in data and data["password1"] != data["password2"]:
raise forms.ValudationError("Passwords must be same")
6.
Problem.
You need a form the fields of which depends on some value in the database. Eg. The field to be shown are customisable per user.
Create a form dynamically
def get_user_form_for_user(user):
class UserForm(forms.Form):
username = forms.CharField()
fields = user.get_profile().all_field()
#Use field to find what to show.
This post provides much more details
7.
Prob. You need to create a Html form which writes to multiple Django models.
Ans. Django forms are not a one to one mapping to Html forms.
#in forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ["username", "email"]
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
#in views.py
def add_user(request):
...
if request.method == "POST":
uform = UserForm(data = request.POST)
pform = UserProfileForm(data = request.POST)
if uform.is_valid() and pform.is_valid():
user = uform.save()
profile = pform.save(commit = False)
profile.user = user
profile.save()
....
...
#in template
<form method="post">
{{ uform.as_p }}
{{ pform.as_p }}
<input type="submit" ...>
</form>
8.
Prob. You want to use multiple forms of same type on one page.
Ans.
a. If you want a datagrid style ui, use formset.
from django.forms.formsets import formset_factory
forms = formset_factory(UserForm, extra = 4)
#
Formsets are described much more comprehensively here
b. If you do not need a datagrid style ui, use prefix argument to forms.
Eg. you have a survey app, and you want a page with all questions from that survey displayed.
#IN views.py
def survey(request, survey_slug)
...
questions = survey.questions.all()
question_forms = []
for question in questions:
qform = QuestionForm(question=question, prefix = question.slug)
question_forms.append(qform)
...
if request.method == "POST":
for question in questions:
qform = QuestionForm(question=question, prefix = question.slug, data = request.POST)
#Validate and do save action
...
...
Do you subscribe to our feed? We recently made a full text feed available, so if you are using the old feed, you should change it. Subscribe now.
Related Posts
- Two Scoops of Django: Review
- Serving static files in Django
- Logging in Django
- Common testing scenarios for Django app.
- Deploying django using docker
Can we help you build amazing apps? Contact us today.
Nice round up of use cases and solutions. This is a good reference for noobs and experienced Django devs. Thanks.