.. index:: django; forms Forms ===== * https://docs.djangoproject.com/en/stable/topics/forms/ * https://docs.djangoproject.com/en/stable/ref/forms/api/ .. contents:: A basic form ------------ .. code-block:: python from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) Processing a form in a view function ------------------------------------ .. code-block:: python def contact(request): if request.method == 'POST': # If the form has been submitted... form = ContactForm(request.POST) # A form bound to the POST data if form.is_valid(): # All validation rules pass # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/thanks/') # Redirect after POST else: form = ContactForm() # An unbound form return render_to_response('contact.html', { 'form': form, }) https://docs.djangoproject.com/en/stable/topics/forms/modelforms/ A model form ------------ .. code-block:: python from django.forms import ModelForm, ValidationError # Create the form class. class ArticleForm(ModelForm): class Meta: model = Article fields = ('name', 'title') # or exclude = ('birth_date') def clean_fieldname(self): if 'fieldname' in self.cleaned_data: data = self.cleaned_data['fieldname'] if not /valid/: raise ValidationError("msg") return data def clean(self): data = self.cleaned_data if not /valid/: raise ValidationError("msg") return data # Creating a form to add an article. form = ArticleForm() ... new_article = form.save() # Creating a form to change an existing article. article = Article.objects.get(pk=1) form = ArticleForm(instance=article) ... form.save() # Create a form to edit an existing Article, but use POST data to populate the form. a = Article.objects.get(pk=1) f = ArticleForm(request.POST, instance=a) f.save() Render form in template ----------------------- .. code-block:: django
{% csrf_token %}
{% if form.non_field_errors %}
{% endif %} {% for field in form %} {% endfor %}
{{ form.non_field_errors }}
{% if field.errors %} {{ field.errors }}
{% endif %} {{ field }} or even {% if field.help_text %}
{{ field.help_text }} {% endif %}
{% csrf_token %}
Read-only form -------------- Call this on the form: .. code-block:: python def make_form_readonly(form): """ Set some attributes on a form's fields that, IN COMBINATION WITH TEMPLATE CHANGES, allow us to display it as read-only. """ # Note that a new BoundField is constructed on the fly when you access # form[name], so any data we want to persist long enough for the template # to access needs to be on the "real" field. We just use the BoundField # to get at the field value. for name in form.fields: field = form.fields[name] bound_field = form[name] if hasattr(field.widget, 'choices'): try: display_value = dict(field.widget.choices)[bound_field.value()] except KeyError: display_value = '' else: display_value = bound_field.value() field.readonly = True field.display_value = display_value Do things like this in the templates: .. code-block:: django {# Date field #} {% if field.field.readonly %} {{ field.value|date:'c' }} {% else %} {% endif %} {# input fields #} {% if field.field.readonly %} {{ field.value }} {% else %} {% endif %} {# select fields #} {% if field.field.readonly %} {{ field.field.display_value }} {% else %} {% endif %} Upload files ------------ Template: .. code-block:: django
{% csrf_token %} {{ form }}
Form class: .. code-block:: python class ImportForm(forms.Form): file = forms.FileField() View: .. code-block:: python @login_required def import_view(request): if request.method == "POST": form = ImportForm(request.POST, request.FILES) if form.is_valid(): handle_uploaded_import(request, request.FILES["file"]) return redirect("links:bookmarks") messages.error(request, "Form not valid") else: form = ImportForm() return render(request, "import.html", {"form": form}) def handle_uploaded_import(request, file): messages.info(request, "importing pages & sections") with transaction.atomic(): data = json.load(file) # ...