Django forms
-
Upload
rubin-damian -
Category
Documents
-
view
242 -
download
6
description
Transcript of Django forms
Django Formsjust the tip of the ice burg
Objectives Explore Django forms API Review the Django forms documentation Create forms using the Django Forms API
Out of the Box Form handling django library Automatically displays HTML form elements Validates submitted data Displays validation errors Automatically converts submitted data into relevant data
types.
Getting Started1. forms.py
2. template rendering
3. models.py
4. views.py
forms.py Forms are composed of fields
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
email = forms.EmailField()
age = forms.IntegerField()
forms.py - fieldsEach field has custom validation logic and other useful hooks.
name = forms.CharField(
label =“Full Name”,
max_length = “50”,
)
email = forms.EmailField(
max_length = “100”,
required = “false”
)
age = forms.IntegerField(
min_value = 18,
)
forms.py - widgetsEach field has a default widget which serves to render html.
name = forms.CharField(
label =“Full Name”,
max_length = “50”,
widget = forms.TextInput(
attrs = { ‘size’ : ’50’, ‘class’ = ‘customClass’ }
)
)
email = forms.EmailField(
max_length = “100”,
required = “false”,
widget = forms.HiddenInput()
)
age = forms.IntegerField(
min_value = 18,
widget = forms.TextInput()
error_messages={’invalid': ’Only numbers please.'}
)
Instantiation : Bound vs Unbound
Unbound forms don’t have data associated with them, but then can be rendered.
form = ContactForm()
Bound forms have specific data associated, which can be validated.
form = ContactForm(data = dataDict)
Initial Data Data displayed only in unbound forms, and are not used as
fallback values if a particular value isn’t provided.
Initial != Default
Can be set two different ways :
1. Set it in the field declaration of your form.
age = forms.IntegerField(initial=18)
2. Set it when you instantiate your form.
form = ContactForm(initial = initialDict)
Form Validation Processform.is_valid()
form._get_errors()
form.full_clean()
form._clean_fields()
for field in form.fields:
value = widget.value_from_datadict(data, files, name)
field.clean(value)
field.to_python(value)
field.validate(value)
field.run_validators(value)
field.clean_fieldname()
form._clean_form()
form.clean()
Form validation
Widget
Field
form
Form Validation Overview Only bound forms may be validated Validation is triggered when form.is_valid() is called Validated, cleaned data is stored in form.cleaned_data Perform the full validation cycle by calling form.full_clean()
Field Validating Three phases for fields: To Python, Validation, and Cleaning If validation raises an Error, cleaning is skipped Validators are callables that can raise a ValidationError Django inlcludes generic ones for common tasks.
URLS, Min/Max Value, Email, etc.
Validators - definingA callable that takes a value and raises a ValidationError; can be useful for reusing validation logic.
App/validators.py
from django.core.exceptions import ValidationError
Import re
def validate_full_name(value):
if len(re.findall(r'\w+', value)) < 2:
raise ValidationError(u’%s is not a full name.’ % value)
Validators - usingfrom django import forms
from projectgroup.project.application.validators import validate_full_name
class ContactForm(forms.Form):
name = forms.CharField(
label =“Full Name”,
max_length = “50”,
validators = [validate_full_name]
)
email = forms.EmailField(
max_length = “100”,
required = “false”
)
age = forms.IntegerField(
min_value = 18,
)
Field Cleaning .clean_fieldname() is called after validators Input has already been converted to Python objects Methods can still raise ValidationError Methods must return the cleaned_value
Specific Field Cleaning Examplefrom django import forms
from projectgroup.project.application.validators import validate_full_name
class ContactForm(forms.Form):
# Everything as before
…
def clean_email(self):
data = self.cleaned_data.get(‘email’, ‘’)
if ‘gmail.com’ not in data:
raise forms.ValidationError(“Why you no like gmail?”)
# always return the cleaned data, whether you have change
# it or not
return data
Form Validation .clean() perform cross-field validation Called even if errors were raised by Fields Must return the cleaned data dictionary ValidationError’s raised by .clean() will be grouped in
form.non_field_errors() by default
Cross-field Cleaning Examplefrom django import forms
from projectgroup.project.application.validators import validate_full_name
class ContactForm(forms.Form):
# Everything as before
…
def clean (self):
cleaned_data = super(ContactForm, self).clean()
age = cleaned_data.get(“age”)
email = cleaned_data.get(“email”)
if not age and not email:
raise forms.ValidationError(“Age and email are required.”)
return cleaned_data
Rendering : Primary ModesThere are three primary output modes :
1. form.as_p()
<p>
<label for=“name”>Name</label>
<input type=“text” id=“name” name=“name” size=“50”/>
</p>
<p>
<label for=“email”>Email</label>
<input type=“text” id=“email” name=“email” size=“50”/>
</p>
<p>
<label for=“age”>Age</label>
<input type=“text” id=“age” name=“age” size=“3”/>
</p>
2. form.as_ul()
3. form.as_table()
Rendering : Controlled Output
{{ field.non_form_errors }}
{% for field in form %}
<div class=“fieldWrapper”>
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
Manually Created<form id=“contact” action=“” method=“get”>
<p>
<label for=“name”>Name</label>
<input type=“text” id=“name” name=“name” size=“50”/>
</p>
<p>
<label for=“email”>Email</label>
<input type=“text” id=“email” name=“email” size=“50”/>
</p>
<p>
<label for=“age”>Age</label>
<input type=“text” id=“age” name=“age” size=“3”/>
</p>
<input type=“submit” name=“save”/>
</form>
Dynamically Created<form id=“contact” action=“” method=“get”>
{{ form.as_p }}
<input type=“submit” name=“save”/>
</form>
<form id=“contact” action=“” method=“get”>
{{ field.non_form_errors }}
{% for field in form %}
<div class=“fieldWrapper”>
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<input type=“submit” name=“save”/>
</form>
Model Forms modelForms map a model to a form validation includes model validators Supports creating and editing instances Key differences from forms
There will be a field for a primary key (id) New save() method New instance attribute
Model Form Exampleapp/models.py
from django import models
class Contact(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
age = models.IntegerField()
app/forms.py
from django import forms
from grp.prj.app.models import Contact
class ContactForm(forms.Modelform):
class Meta:
model = Contact
Limiting Fields Specify fields to expose, or fields to exclude
app/forms.py
from django import forms
from grp.prj.app.models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ('name', 'email',)
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
exclude = (’age',)
Instantiating Model Forms Like before, we may have bound and unbound Model Forms
Unbound
mform = ContactForm()
Bound
mform = ContactForm(instance=Contact.objects.get(id=2) )
Handling forms in views.py1. Import your form(s)
2. Within your view function1. Check for submission(GET or POST).
1. If submitted1. bind the form to the data.
2. Validate.
1. If its valid, do stuff.
2. Otherwise let it remain unbound.
3. Pass form to the context
4. Render your page.
views.py examplefrom grp.prj.app.forms import ContactForm
…
def contactView(request):
context = {}
contactPDA = Dpdpcntc()
…
initials = {
‘age' : ’18'
}
#instantiate
if request.GET.get(‘submit’):
form = ContactForm(data = request.GET)
if form.is_valid():
….
else:
form = ContactForm(initial=initials)
context[‘form’] = form
return render_to_response(…)
Import Form
Check for submission
Bind Form
Form Validation
Unbound Form
Render HTMLForm in Context
views.py – other examplesif request.GET.get(‘submit’):
form = ContactForm(request.GET)
if form.is_valid():
….
else:
form = ContactForm(initial=initials)
if request.GET:
form = ContactForm(request.GET)
if form.is_valid():
….
else:
form = ContactForm(initial=initials)
form = ContactForm(data=request.GET or None, initial=initials)
if form.is_valid():
….
FinQuestions?