============= The Forms API ============= .. module:: django.forms .. admonition:: About this document This document covers the gritty details of Django's forms API. You should read the :doc:`introduction to working with forms ` first. .. _ref-forms-api-bound-unbound: Bound and unbound forms ======================= A :class:`Form` instance is either **bound** to a set of data, or **unbound**. * If it's **bound** to a set of data, it's capable of validating that data and rendering the form as HTML with the data displayed in the HTML. * If it's **unbound**, it cannot do validation (because there's no data to validate!), but it can still render the blank form as HTML. .. class:: Form To create an unbound :class:`Form` instance, instantiate the class: .. code-block:: pycon >>> f = ContactForm() To bind data to a form, pass the data as a dictionary as the first parameter to your :class:`Form` class constructor: .. code-block:: pycon >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data) In this dictionary, the keys are the field names, which correspond to the attributes in your :class:`Form` class. The values are the data you're trying to validate. These will usually be strings, but there's no requirement that they be strings; the type of data you pass depends on the :class:`Field`, as we'll see in a moment. .. attribute:: Form.is_bound If you need to distinguish between bound and unbound form instances at runtime, check the value of the form's :attr:`~Form.is_bound` attribute: .. code-block:: pycon >>> f = ContactForm() >>> f.is_bound False >>> f = ContactForm({'subject': 'hello'}) >>> f.is_bound True Note that passing an empty dictionary creates a *bound* form with empty data: .. code-block:: pycon >>> f = ContactForm({}) >>> f.is_bound True If you have a bound :class:`Form` instance and want to change the data somehow, or if you want to bind an unbound :class:`Form` instance to some data, create another :class:`Form` instance. There is no way to change data in a :class:`Form` instance. Once a :class:`Form` instance has been created, you should consider its data immutable, whether it has data or not. Using forms to validate data ============================ .. method:: Form.clean() Implement a ``clean()`` method on your ``Form`` when you must add custom validation for fields that are interdependent. See :ref:`validating-fields-with-clean` for example usage. .. method:: Form.is_valid() The primary task of a :class:`Form` object is to validate data. With a bound :class:`Form` instance, call the :meth:`~Form.is_valid` method to run validation and return a boolean designating whether the data was valid: .. code-block:: pycon >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data) >>> f.is_valid() True Let's try with some invalid data. In this case, ``subject`` is blank (an error, because all fields are required by default) and ``sender`` is not a valid email address: .. code-block:: pycon >>> data = {'subject': '', ... 'message': 'Hi there', ... 'sender': 'invalid email address', ... 'cc_myself': True} >>> f = ContactForm(data) >>> f.is_valid() False .. attribute:: Form.errors Access the :attr:`~Form.errors` attribute to get a dictionary of error messages: .. code-block:: pycon >>> f.errors {'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']} In this dictionary, the keys are the field names, and the values are lists of strings representing the error messages. The error messages are stored in lists because a field can have multiple error messages. You can access :attr:`~Form.errors` without having to call :meth:`~Form.is_valid` first. The form's data will be validated the first time either you call :meth:`~Form.is_valid` or access :attr:`~Form.errors`. The validation routines will only get called once, regardless of how many times you access :attr:`~Form.errors` or call :meth:`~Form.is_valid`. This means that if validation has side effects, those side effects will only be triggered once. .. method:: Form.errors.as_data() Returns a ``dict`` that maps fields to their original ``ValidationError`` instances. >>> f.errors.as_data() {'sender': [ValidationError(['Enter a valid email address.'])], 'subject': [ValidationError(['This field is required.'])]} Use this method anytime you need to identify an error by its ``code``. This enables things like rewriting the error's message or writing custom logic in a view when a given error is present. It can also be used to serialize the errors in a custom format (e.g. XML); for instance, :meth:`~Form.errors.as_json()` relies on ``as_data()``. The need for the ``as_data()`` method is due to backwards compatibility. Previously ``ValidationError`` instances were lost as soon as their **rendered** error messages were added to the ``Form.errors`` dictionary. Ideally ``Form.errors`` would have stored ``ValidationError`` instances and methods with an ``as_`` prefix could render them, but it had to be done the other way around in order not to break code that expects rendered error messages in ``Form.errors``. .. method:: Form.errors.as_json(escape_html=False) Returns the errors serialized as JSON. >>> f.errors.as_json() {"sender": [{"message": "Enter a valid email address.", "code": "invalid"}], "subject": [{"message": "This field is required.", "code": "required"}]} By default, ``as_json()`` does not escape its output. If you are using it for something like AJAX requests to a form view where the client interprets the response and inserts errors into the page, you'll want to be sure to escape the results on the client-side to avoid the possibility of a cross-site scripting attack. You can do this in JavaScript with ``element.textContent = errorText`` or with jQuery's ``$(el).text(errorText)`` (rather than its ``.html()`` function). If for some reason you don't want to use client-side escaping, you can also set ``escape_html=True`` and error messages will be escaped so you can use them directly in HTML. .. method:: Form.errors.get_json_data(escape_html=False) Returns the errors as a dictionary suitable for serializing to JSON. :meth:`Form.errors.as_json()` returns serialized JSON, while this returns the error data before it's serialized. The ``escape_html`` parameter behaves as described in :meth:`Form.errors.as_json()`. .. method:: Form.add_error(field, error) This method allows adding errors to specific fields from within the ``Form.clean()`` method, or from outside the form altogether; for instance from a view. The ``field`` argument is the name of the field to which the errors should be added. If its value is ``None`` the error will be treated as a non-field error as returned by :meth:`Form.non_field_errors() `. The ``error`` argument can be a string, or preferably an instance of ``ValidationError``. See :ref:`raising-validation-error` for best practices when defining form errors. Note that ``Form.add_error()`` automatically removes the relevant field from ``cleaned_data``. .. method:: Form.has_error(field, code=None) This method returns a boolean designating whether a field has an error with a specific error ``code``. If ``code`` is ``None``, it will return ``True`` if the field contains any errors at all. To check for non-field errors use :data:`~django.core.exceptions.NON_FIELD_ERRORS` as the ``field`` parameter. .. method:: Form.non_field_errors() This method returns the list of errors from :attr:`Form.errors ` that aren't associated with a particular field. This includes ``ValidationError``\s that are raised in :meth:`Form.clean() ` and errors added using :meth:`Form.add_error(None, "...") `. Behavior of unbound forms ------------------------- It's meaningless to validate a form with no data, but, for the record, here's what happens with unbound forms: .. code-block:: pycon >>> f = ContactForm() >>> f.is_valid() False >>> f.errors {} .. _ref-forms-initial-form-values: Initial form values =================== .. attribute:: Form.initial Use :attr:`~Form.initial` to declare the initial value of form fields at runtime. For example, you might want to fill in a ``username`` field with the username of the current session. To accomplish this, use the :attr:`~Form.initial` argument to a :class:`Form`. This argument, if given, should be a dictionary mapping field names to initial values. Only include the fields for which you're specifying an initial value; it's not necessary to include every field in your form. For example: .. code-block:: pycon >>> f = ContactForm(initial={'subject': 'Hi there!'}) These values are only displayed for unbound forms, and they're not used as fallback values if a particular value isn't provided. If a :class:`~django.forms.Field` defines :attr:`~Field.initial` *and* you include :attr:`~Form.initial` when instantiating the ``Form``, then the latter ``initial`` will have precedence. In this example, ``initial`` is provided both at the field level and at the form instance level, and the latter gets precedence: .. code-block:: pycon >>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(initial='class') ... url = forms.URLField() ... comment = forms.CharField() >>> f = CommentForm(initial={'name': 'instance'}, auto_id=False) >>> print(f)
Name:
Url:
Comment:
.. method:: Form.get_initial_for_field(field, field_name) Returns the initial data for a form field. It retrieves the data from :attr:`Form.initial` if present, otherwise trying :attr:`Field.initial`. Callable values are evaluated. It is recommended to use :attr:`BoundField.initial` over :meth:`~Form.get_initial_for_field()` because ``BoundField.initial`` has a simpler interface. Also, unlike :meth:`~Form.get_initial_for_field()`, :attr:`BoundField.initial` caches its values. This is useful especially when dealing with callables whose return values can change (e.g. ``datetime.now`` or ``uuid.uuid4``): .. code-block:: pycon >>> import uuid >>> class UUIDCommentForm(CommentForm): ... identifier = forms.UUIDField(initial=uuid.uuid4) >>> f = UUIDCommentForm() >>> f.get_initial_for_field(f.fields['identifier'], 'identifier') UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334') >>> f.get_initial_for_field(f.fields['identifier'], 'identifier') UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0') >>> # Using BoundField.initial, for comparison >>> f['identifier'].initial UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30') >>> f['identifier'].initial UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30') Checking which form data has changed ==================================== .. method:: Form.has_changed() Use the ``has_changed()`` method on your ``Form`` when you need to check if the form data has been changed from the initial data. >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data, initial=data) >>> f.has_changed() False When the form is submitted, we reconstruct it and provide the original data so that the comparison can be done: >>> f = ContactForm(request.POST, initial=data) >>> f.has_changed() ``has_changed()`` will be ``True`` if the data from ``request.POST`` differs from what was provided in :attr:`~Form.initial` or ``False`` otherwise. The result is computed by calling :meth:`Field.has_changed` for each field in the form. .. attribute:: Form.changed_data The ``changed_data`` attribute returns a list of the names of the fields whose values in the form's bound data (usually ``request.POST``) differ from what was provided in :attr:`~Form.initial`. It returns an empty list if no data differs. >>> f = ContactForm(request.POST, initial=data) >>> if f.has_changed(): ... print("The following fields changed: %s" % ", ".join(f.changed_data)) >>> f.changed_data ['subject', 'message'] Accessing the fields from the form ================================== .. attribute:: Form.fields You can access the fields of :class:`Form` instance from its ``fields`` attribute: .. code-block:: pycon >>> for row in f.fields.values(): print(row) ... >>> f.fields['name'] You can alter the field and :class:`.BoundField` of :class:`Form` instance to change the way it is presented in the form: .. code-block:: pycon >>> f.as_div().split("")[0] '
' >>> f["subject"].label = "Topic" >>> f.as_div().split("
")[0] '
' Beware not to alter the ``base_fields`` attribute because this modification will influence all subsequent ``ContactForm`` instances within the same Python process: .. code-block:: pycon >>> f.base_fields["subject"].label_suffix = "?" >>> another_f = CommentForm(auto_id=False) >>> f.as_div().split("
")[0] '
' Accessing "clean" data ====================== .. attribute:: Form.cleaned_data Each field in a :class:`Form` class is responsible not only for validating data, but also for "cleaning" it -- normalizing it to a consistent format. This is a nice feature, because it allows data for a particular field to be input in a variety of ways, always resulting in consistent output. For example, :class:`~django.forms.DateField` normalizes input into a Python ``datetime.date`` object. Regardless of whether you pass it a string in the format ``'1994-07-15'``, a ``datetime.date`` object, or a number of other formats, ``DateField`` will always normalize it to a ``datetime.date`` object as long as it's valid. Once you've created a :class:`~Form` instance with a set of data and validated it, you can access the clean data via its ``cleaned_data`` attribute: .. code-block:: pycon >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data) >>> f.is_valid() True >>> f.cleaned_data {'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'} Note that any text-based field -- such as ``CharField`` or ``EmailField`` -- always cleans the input into a string. We'll cover the encoding implications later in this document. If your data does *not* validate, the ``cleaned_data`` dictionary contains only the valid fields: .. code-block:: pycon >>> data = {'subject': '', ... 'message': 'Hi there', ... 'sender': 'invalid email address', ... 'cc_myself': True} >>> f = ContactForm(data) >>> f.is_valid() False >>> f.cleaned_data {'cc_myself': True, 'message': 'Hi there'} ``cleaned_data`` will always *only* contain a key for fields defined in the ``Form``, even if you pass extra data when you define the ``Form``. In this example, we pass a bunch of extra fields to the ``ContactForm`` constructor, but ``cleaned_data`` contains only the form's fields: .. code-block:: pycon >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True, ... 'extra_field_1': 'foo', ... 'extra_field_2': 'bar', ... 'extra_field_3': 'baz'} >>> f = ContactForm(data) >>> f.is_valid() True >>> f.cleaned_data # Doesn't contain extra_field_1, etc. {'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'} When the ``Form`` is valid, ``cleaned_data`` will include a key and value for *all* its fields, even if the data didn't include a value for some optional fields. In this example, the data dictionary doesn't include a value for the ``nick_name`` field, but ``cleaned_data`` includes it, with an empty value: .. code-block:: pycon >>> from django import forms >>> class OptionalPersonForm(forms.Form): ... first_name = forms.CharField() ... last_name = forms.CharField() ... nick_name = forms.CharField(required=False) >>> data = {'first_name': 'John', 'last_name': 'Lennon'} >>> f = OptionalPersonForm(data) >>> f.is_valid() True >>> f.cleaned_data {'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'} In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat empty values as an empty string. Each field type knows what its "blank" value is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For full details on each field's behavior in this case, see the "Empty value" note for each field in the "Built-in ``Field`` classes" section below. You can write code to perform validation for particular form fields (based on their name) or for the form as a whole (considering combinations of various fields). More information about this is in :doc:`/ref/forms/validation`. .. _ref-forms-api-outputting-html: Outputting forms as HTML ======================== The second task of a ``Form`` object is to render itself as HTML. To do so, ``print`` it: .. code-block:: pycon >>> f = ContactForm() >>> print(f)
If the form is bound to data, the HTML output will include that data appropriately. For example, if a field is represented by an ````, the data will be in the ``value`` attribute. If a field is represented by an ````, then that HTML will include ``checked`` if appropriate: .. code-block:: pycon >>> data = {'subject': 'hello', ... 'message': 'Hi there', ... 'sender': 'foo@example.com', ... 'cc_myself': True} >>> f = ContactForm(data) >>> print(f)
This default output wraps each field with a ``
``. Notice the following: * For flexibility, the output does *not* include the ``
`` and ``
`` tags or an ```` tag. It's your job to do that. * Each field type has a default HTML representation. ``CharField`` is represented by an ```` and ``EmailField`` by an ````. ``BooleanField(null=False)`` is represented by an ````. Note these are merely sensible defaults; you can specify which HTML to use for a given field by using widgets, which we'll explain shortly. * The HTML ``name`` for each tag is taken directly from its attribute name in the ``ContactForm`` class. * The text label for each field -- e.g. ``'Subject:'``, ``'Message:'`` and ``'Cc myself:'`` is generated from the field name by converting all underscores to spaces and upper-casing the first letter. Again, note these are merely sensible defaults; you can also specify labels manually. * Each text label is surrounded in an HTML ``