# Django 6.0.7 문서

# 폼을 사용하여 작업하기

이 문서에 대해서

이 문서는 웹 폼의 기초적인 사항과 웹 폼이 Django에서 어떻게 다루어지는지에 대한 소개를 제공합니다. 폼 API의 세부 영역에 대한 자세한 내용은 The Forms API, Form fields, :doc:`/ref/forms/validation`을 참조하세요.

아무것도 하지않고 단지 컨텐츠를 퍼블리싱하는 웹사이트 혹은 어플리케이션을 계획중인게 아니라면, 그리고 어떠한 정보로 방문자로부터 입력받지 않을 것이 아니라면 폼 사용법을 이해 할 필요가 있습니다.

Django는 사용자로 부터 입력을 받고, 이를 처리하고 응답할 폼을 생성하는 다양한 도구와 라이브러리를 제공합니다.

## HTML 폼

HTML에서 폼은 사용자가 텍스트를 입력하고, 옵션을 선택하고, 오브젝트나 제어 요소를 조작하는 등의 작업을 수행한 다음 해당 정보를 서버로 전송할 수 있도록 하는 <form>…</form> 내부의 요소 모음입니다.

텍스트 입력이나 체크박스 등 일부 폼 인터페이스 요소는 HTML 자체에 내장되어 있습니다. 날짜 선택기를 띄우거나 슬라이더를 움직이거나 컨트롤을 조작할 수 있는 인터페이스는 일반적으로 이러한 효과를 내기 위해 HTML 폼 <input> 요소뿐만 아니라 JavaScript 및 CSS를 사용합니다.

폼은 <input> 요소와 함께 두 가지를 지정해야 합니다:

- 위치: 사용자의 입력에 해당하는 데이터를 반환해야 하는 URL입니다.

- 방법: 데이터를 반환할 HTTP 메서드입니다.

예를 들어, Django 관리자의 로그인 폼에는 username에 대한 type=”text”, password에 대한 type=”password”, “Log in” 버튼에 대한 type=”submit” 등 여러 <input> 요소가 포함되어 있습니다. 또한 사용자가 볼 수 없는 몇 가지 숨겨진 텍스트 필드가 포함되어 있으며, Django는 이를 사용하여 다음에 수행할 작업을 결정합니다.

또한 브라우저에 폼 데이터가 <form>의 action 속성 - /admin/ -에 지정된 URL로 전송되어야 하며 메소드 속성 - post - 에 지정된 HTTP 메커니즘을 사용하여 전송되어야 함을 알립니다.

<input type=”submit” value=”Log in”> 요소가 트리거되면 데이터가 /admin/으로 반환됩니다.

### `GET` 과 `POST`

폼을 처리할 때 사용할 수 있는 메서드는 GET과 POST가 전부입니다.

Django의 로그인 폼은 `POST` 메서드를 사용하여 반환되는데, 브라우저는 폼 데이터를 번들로 묶어 전송을 위해 인코딩하고 서버로 전송한 다음 응답을 다시 받습니다.

반면 `GET``은 제출된 데이터를 문자열로 묶고 이를 사용하여 URL을 작성합니다. URL에는 데이터를 전송해야 하는 주소와 데이터 키 및 값이 포함됩니다. Django 문서에서 검색을 수행하면 ``https://docs.djangoproject.com/search/?q=forms&release=1` 형식의 URL이 생성되는 것을 확인할 수 있습니다.

‘GET``과 ‘POST``는 일반적으로 다른 용도로 사용됩니다.

시스템 상태를 변경하는 데 사용될 수 있는 모든 요청(예: 데이터베이스를 변경하는 요청)은 ``POST``를 사용해야 합니다. GET``은 시스템 상태에 영향을 주지 않는 요청에만 사용해야 합니다.

‘GET’은 비밀번호가 URL과 브라우저 기록 및 서버 로그에 모두 일반 텍스트로 표시되기 때문에 비밀번호 양식에도 적합하지 않습니다. 또한 대량의 데이터나 이미지와 같은 바이너리 데이터에도 적합하지 않습니다. 관리자 양식에 `GET` 요청을 사용하는 웹 애플리케이션은 공격자가 양식의 요청을 모방하여 시스템의 민감한 부분에 쉽게 액세스할 수 있기 때문에 보안 위험이 있습니다. ‘``POST``를 Django의 :doc:`CSRF protection`과 같은 다른 보호 기능과 함께 사용하면 액세스에 대한 제어를 더욱 강화할 수 있습니다.

반면에 `GET``은 ``GET` 요청을 나타내는 URL을 쉽게 북마크, 공유 또는 다시 제출할 수 있으므로 웹 검색 양식과 같은 것에 적합합니다.

## 폼에서 Django의 역할

양식을 처리하는 것은 복잡한 작업입니다. 여러 가지 유형의 수많은 데이터 항목을 양식에 표시할 수 있도록 준비하고, HTML로 렌더링하고, 편리한 인터페이스를 사용하여 편집하고, 서버로 반환하고, 유효성을 검사하고 정리한 다음, 추가 처리를 위해 저장하거나 전달해야 하는 Django의 관리자를 생각해 보시기 바랍니다.

Django의 양식 기능은 이러한 작업의 상당 부분을 단순화하고 자동화할 수 있으며, 대부분의 프로그래머가 직접 작성한 코드에서 수행하는 것보다 더 안전하게 수행할 수 있습니다.

Django는 폼과 관련된 작업의 세 가지 구분된 영역을 처리합니다:

- 렌더링할 수 있도록 데이터를 준비하고 재구성합니다.

- 해당 데이터에 대한 HTML 양식 생성

- 클라이언트로부터 제출된 양식 및 데이터 수신 및 처리

이 모든 작업을 수동으로 수행하는 코드를 작성하는 것은 가능하지만 Django가 이 모든 작업을 대신 처리할 수 있습니다.

## Forms in Django

HTML 양식에 대해 간략하게 설명했지만 HTML <Form>은 필요한 메커니즘의 한 부분일 뿐입니다.

웹 애플리케이션의 컨텍스트에서 ‘양식’은 해당 HTML <form>, 또는 이를 생성하는 Django `Form`, 또는 제출 시 반환되는 구조화된 데이터 또는 이러한 부분들의 포괄적인 동작 전체를 지칭할 수 있습니다.

### The Django `Form` class

이 컴포넌트 시스템의 핵심은 Django의 `Form` 클래스입니다. Django 모델이 객체의 논리적 구조, 동작 및 객체의 부분들이 어떻게 표시되는지를 설명하는 것과 마찬가지로, `Form` 클래스는 폼을 설명하고 폼이 어떻게 작동하고 표시되는지를 결정합니다.

모델 클래스의 필드가 데이터베이스 필드에 매핑되는 것과 비슷한 방식으로, 폼 클래스의 필드는 HTML 폼 <input> 요소에 매핑됩니다. (:class:`ModelForm`은 모델 클래스의 필드를 :class:`Form`을 통해 HTML 양식 <input> 요소에 매핑합니다. Django admin은 이를 기반으로 합니다).

양식의 각 필드는 그 자체로 클래스이며, 양식 데이터를 관리하고 양식이 제출될 때 유효성 검사를 수행합니다. A :class:`DateField`와 a :class:`FileField`는 매우 다른 종류의 데이터를 처리하며 다른 작업을 수행해야 합니다.

양식 필드는 브라우저에서 사용자에게 HTML “widget”(사용자 인터페이스 도구)으로 표시됩니다. 각 필드 유형에는 적절한 기본값인 :doc:`Widget class`이 있지만 필요에 따라 이를 재정의할 수 있습니다.

### 양식 인스턴스화, 처리 및 렌더링

Django에서 객체를 렌더링할 때는 일반적으로 다음과 같이 합니다:

1. 뷰에서 해당 객체를 가져옵니다(예: 데이터베이스에서 가져오기).

2. 템플릿 컨텍스트로 전달합니다.

3. 템플릿 변수를 사용하여 HTML 마크업으로 전개합니다.

템플릿에서 양식을 렌더링하는 작업은 다른 종류의 객체를 렌더링하는 작업과 거의 동일하지만 몇 가지 주요 차이점이 있습니다.

데이터가 포함되지 않은 모델 인스턴스의 경우 템플릿에서 이 데이터로 무언가를 하는 것이 거의 유용하지 않을 것입니다. 반면에 채워지지 않은 양식을 렌더링하는 것은 사용자가 양식을 채우기를 원할 때 매우 적합합니다.

따라서 뷰에서 모델 인스턴스를 처리할 때는 일반적으로 데이터베이스에서 조회합니다. 폼을 처리할 때는 일반적으로 뷰에서 폼을 인스턴스화합니다.

양식을 인스턴스화할 때는 양식을 비워두거나 다음과 같이 미리 채우도록 선택할 수 있습니다:

- 저장된 모델 인스턴스의 데이터( 수정하기 위한 관리자 양식의 경우처럼)

- 다른 출처에서 수집한 데이터

- 이전 HTML 양식 제출에서 받은 데이터

마지막 사례는 가장 흥미로운데, 사용자가 웹사이트를 읽는 데 그치지 않고 정보를 다시 웹사이트로 보낼 수 있게 해주기 때문입니다.

## Building a form

### 필요한 작업

사용자의 이름을 얻기 위해 웹사이트에 간단한 양식을 만들고 싶다고 가정해 보겠습니다. 템플릿에 다음과 같은 내용이 필요합니다:

    <form action="/your-name/" method="post">
        <label for="your_name">Your name: </label>
        <input id="your_name" type="text" name="your_name" value="{{ current_name }}">
        <input type="submit" value="OK">
    </form>

이렇게 하면 브라우저가 `POST` 메서드를 사용하여 양식 데이터를 URL `/your-name/``으로 반환하도록 지시합니다. 그러면 "Your name:"이라는 레이블이 붙은 텍스트 필드와 "OK"이라고 표시된 버튼이 표시됩니다. 템플릿 컨텍스트에 ``current_name` 변수가 포함되어 있으면 이 변수가 `your_name` 필드를 미리 채우는 데 사용됩니다.

HTML 양식이 포함된 템플릿을 렌더링하고 ‘current_name’ 필드를 적절히 제공할 수 있는 뷰가 필요합니다.

양식이 제출되면 서버로 전송되는 `POST` 요청에 양식 데이터가 포함됩니다.

이제 요청에서 적절한 키/값 쌍을 찾은 다음 처리할 `/your-name/` URL에 해당하는 뷰도 필요합니다.

이것은 매우 간단한 양식입니다. 실제로 양식에는 수십 또는 수백 개의 필드가 포함될 수 있으며, 이 중 많은 필드를 미리 채워야 할 수도 있으며, 사용자가 작업을 완료하기 전에 편집-제출 주기를 여러 번 수행해야 할 수도 있습니다.

양식이 제출되기 전에도 브라우저에서 일부 유효성 검사를 수행해야 할 수도 있고, 사용자가 달력에서 날짜를 선택하는 등의 작업을 수행할 수 있도록 훨씬 더 복잡한 필드를 사용해야 할 수도 있습니다.

이 단계에서는 Django가 이 작업의 대부분을 대신 수행하도록 하는 것이 훨씬 쉽습니다.

### Building a form in Django

#### The `Form` class

원하는 HTML 양식의 모양을 이미 정했습니다. Django에서 이를 구현하기 위한 시작점은 다음과 같습니다:

`forms.py`

    from django import forms

    class NameForm(forms.Form):
        your_name = forms.CharField(label="Your name", max_length=100)

단일 필드(`your_name`)가 있는 `Form` 클래스를 정의합니다. 필드가 렌더링될 때 <label>에 표시되는 인간 친화적인 레이블을 필드에 적용했습니다(이 사례에서 지정한 :attr:`~Field.label`은 사실 생략했더라도 자동으로 생성되는 것과 동일한 레이블입니다).

필드의 최대 허용 길이는 :attr:`~CharField..max_length`에 의해 정의됩니다. 이것은 두 가지 작업을 수행합니다. HTML <input>에 ``maxlength=”100”``을 설정합니다(따라서 브라우저는 사용자가 애초에 해당 문자 수 이상을 입력하지 못하도록 해야 합니다). 또한 Django가 브라우저에서 양식을 수신할 때 데이터 길이의 유효성을 검사한다는 의미이기도 합니다.

A `Form` instance has an `is_valid()` method, which runs validation routines for all its fields. When this method is called, if all fields contain valid data, it will:

- True 을 반환합니다.

- 양식의 데이터를 `cleaned_data` 속성에 배치합니다.

전체 양식은 처음 렌더링될 때 다음과 같이 표시됩니다:

    <label for="your_name">Your name: </label>
    <input id="your_name" type="text" name="your_name" maxlength="100" required>

<form> 태그나 제출 버튼이 포함되어 있지 않다는 점에 유의하세요. 템플릿에서 직접 제공해야 합니다.

#### The view

Django 웹사이트로 반환된 양식 데이터는 일반적으로 양식을 게시한 뷰와 동일한 뷰에서 처리됩니다. 따라서 동일한 로직을 일부 재사용할 수 있습니다.

양식을 처리하려면 게시할 URL에 대한 뷰에서 양식을 인스턴스화해야 합니다:

`views.py`

    from django.http import HttpResponseRedirect
    from django.shortcuts import render

    from .forms import NameForm

    def get_name(request):
        # if this is a POST request we need to process the form data
        if request.method == "POST":
            # create a form instance and populate it with data from the request:
            form = NameForm(request.POST)
            # check whether it's valid:
            if form.is_valid():
                # process the data in form.cleaned_data as required
                # ...
                # redirect to a new URL:
                return HttpResponseRedirect("/thanks/")

        # if a GET (or any other method) we'll create a blank form
        else:
            form = NameForm()

        return render(request, "name.html", {"form": form})

이 뷰에 `GET` 요청이 도착하면 빈 양식 인스턴스가 생성되고 템플릿 컨텍스트에 배치되어 렌더링됩니다. 이것이 URL을 처음 방문했을 때 예상할 수 있는 상황입니다.

폼이 `POST` 요청을 사용하여 제출되는 경우 뷰는 다시 한 번 폼 인스턴스를 만들고 요청의 데이터로 채웁니다: `form = NameForm(request.POST)` 이를 “폼에 데이터 바인딩”이라고 합니다(이제 바인딩된 폼이 됩니다).

양식의 `is_valid()` 메서드를 호출하고, ``True``가 아닌 경우 양식과 함께 템플릿으로 돌아갑니다. 이번에는 양식이 더 이상 비어 있지 않으므로(*바인딩되지 않음) 이전에 제출한 데이터로 HTML 양식이 채워지고 필요에 따라 편집 및 수정할 수 있습니다.

is_valid()``가 `True``이면 이제 ``cleaned_data` 속성에서 모든 유효성 검사된 양식 데이터를 찾을 수 있습니다. 이 데이터를 사용하여 데이터베이스를 업데이트하거나 다른 처리를 수행한 후 브라우저에 다음 행선지를 알려주는 HTTP 리디렉션을 보낼 수 있습니다.

#### The template

name.html`` 템플릿에서는 많은 작업을 할 필요가 없습니다:

    <form action="/your-name/" method="post">
        {% csrf_token %}
        {{ form }}
        <input type="submit" value="Submit">
    </form>

양식의 모든 필드와 해당 속성은 Django의 템플릿 언어에 의해 해당 ``{{ form }}``에서 HTML 마크업으로 압축 해제됩니다.

양식 및 교차 사이트 요청 위조 방지

Django ships with an easy-to-use protection against Cross Site Request Forgeries. When submitting a form via `POST` with CSRF protection enabled you must use the `csrf_token` template tag as in the preceding example. However, since CSRF protection is not directly tied to forms in templates, this tag is omitted from the following examples in this document.

HTML5 input types and browser validation

If your form includes a `URLField`, an `EmailField` or any integer field type, Django will use the `url`, `email` and `number` HTML5 input types. By default, browsers may apply their own validation on these fields, which may be stricter than Django’s validation. If you would like to disable this behavior, set the `novalidate` attribute on the `form` tag, or specify a different widget on the field, like `TextInput`.

We now have a working web form, described by a Django `Form`, processed by a view, and rendered as an HTML `<form>`.

That’s all you need to get started, but the forms framework puts a lot more at your fingertips. Once you understand the basics of the process described above, you should be prepared to understand other features of the forms system and ready to learn a bit more about the underlying machinery.

## More about Django `Form` classes

All form classes are created as subclasses of either `django.forms.Form` or `django.forms.ModelForm`. You can think of `ModelForm` as a subclass of `Form`. `Form` and `ModelForm` actually inherit common functionality from a (private) `BaseForm` class, but this implementation detail is rarely important.

Models and Forms

In fact if your form is going to be used to directly add or edit a Django model, a ModelForm can save you a great deal of time, effort, and code, because it will build a form, along with the appropriate fields and their attributes, from a `Model` class.

### Bound and unbound form instances

The distinction between Bound and unbound forms is important:

- An unbound form has no data associated with it. When rendered to the user, it will be empty or will contain default values.

- A bound form has submitted data, and hence can be used to tell if that data is valid. If an invalid bound form is rendered, it can include inline error messages telling the user what data to correct.

The form’s `is_bound` attribute will tell you whether a form has data bound to it or not.

### More on fields

Consider a more useful form than our minimal example above, which we could use to implement “contact me” functionality on a personal website:

`forms.py`

    from django import forms

    class ContactForm(forms.Form):
        subject = forms.CharField(max_length=100)
        message = forms.CharField(widget=forms.Textarea)
        contact_email = forms.EmailField()
        urgent = forms.BooleanField(required=False)

Our earlier form used a single field, `your_name`, a `CharField`. In this case, our form has four fields: `subject`, `message`, `contact_email` and `urgent`. `CharField`, `EmailField` and `BooleanField` are just three of the available field types; a full list can be found in Form fields.

#### Widgets

Each form field has a corresponding Widget class, which in turn corresponds to an HTML form widget such as `<input type="text">`.

In most cases, the field will have a sensible default widget. For example, by default, a `CharField` will have a `TextInput` widget, that produces an `<input type="text">` in the HTML. If you needed `<textarea>` instead, you’d specify the appropriate widget when defining your form field, as we have done for the `message` field.

#### Field data

Whatever the data submitted with a form, once it has been successfully validated by calling `is_valid()` (and `is_valid()` has returned `True`), the validated form data will be in the `form.cleaned_data` dictionary. This data will have been nicely converted into Python types for you.

참고

You can still access the unvalidated data directly from `request.POST` at this point, but the validated data is better.

In the contact form example above, `urgent` will be a boolean value. Likewise, fields such as `IntegerField` and `FloatField` convert values to a Python `int` and `float` respectively.

Here’s how the form data could be processed in the view that handles this form:

`views.py`

    from django.core.mail import EmailMessage

    if form.is_valid():
        subject = form.cleaned_data["subject"]
        message = form.cleaned_data["message"]
        contact_email = form.cleaned_data["contact_email"]
        urgent = form.cleaned_data["urgent"]

        body = (
            "Submitted through the contact form.\n"
            f"Contact email (unverified): {contact_email}\n"
            f"Marked urgent: {'yes' if urgent else 'no'}\n"
            f"Message:\n{message}"
        )

        # Send the message, directing replies to the contact_email.
        EmailMessage(
            subject=f"[contact form] {subject}",
            body=body,
            from_email="contact-form@example.com",
            to=["info@example.com"],
            headers={"Importance": "high"} if urgent else None,
            reply_to=[contact_email],
        ).send()

        return HttpResponseRedirect("/thanks/")

팁

For more on sending email from Django, see 이메일 보내기.

Some field types need some extra handling. For example, files that are uploaded using a form need to be handled differently (they can be retrieved from `request.FILES`, rather than `request.POST`). For details of how to handle file uploads with your form, see Binding uploaded files to a form.

## Working with form templates

All you need to do to get your form into a template is to place the form instance into the template context. So if your form is called `form` in the context, `{{ form }}` will render its `<label>` and `<input>` elements appropriately.

Additional form template furniture

Don’t forget that a form’s output does not include the surrounding `<form>` tags, or the form’s `submit` control. You will have to provide these yourself.

### Reusable form templates

The HTML output when rendering a form is itself generated via a template. You can control this by creating an appropriate template file and setting a custom `FORM_RENDERER` to use that `form_template_name` site-wide. You can also customize per-form by overriding the form’s `template_name` attribute to render the form using the custom template, or by passing the template name directly to `Form.render()`.

The example below will result in `{{ form }}` being rendered as the output of the `form_snippet.html` template.

In your templates:

    # In your template:
    {{ form }}

    # In form_snippet.html:
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }} {{ field }}
        </div>
    {% endfor %}

Then you can configure the `FORM_RENDERER` setting:

`settings.py`

    from django.forms.renderers import TemplatesSetting

    class CustomFormRenderer(TemplatesSetting):
        form_template_name = "form_snippet.html"

    FORM_RENDERER = "project.settings.CustomFormRenderer"

… or for a single form:

    class MyForm(forms.Form):
        template_name = "form_snippet.html"
        ...

… or for a single render of a form instance, passing in the template name to the `Form.render()`. Here’s an example of this being used in a view:

    def index(request):
        form = MyForm()
        rendered_form = form.render("form_snippet.html")
        context = {"form": rendered_form}
        return render(request, "index.html", context)

See Outputting forms as HTML for more details.

### Reusable field group templates

Each field is available as an attribute of the form, using `{{ form.name_of_field }}` in a template. A field has an `as_field_group()` method which renders the related elements of the field as a group: its label, widget, errors, and help text.

This allows generic templates to be written that arrange each field’s elements in the required layout. For example:

    {{ form.non_field_errors }}
    <div class="fieldWrapper">
      {{ form.subject.as_field_group }}
    </div>
    <div class="fieldWrapper">
      {{ form.message.as_field_group }}
    </div>
    <div class="fieldWrapper">
      {{ form.contact_email.as_field_group }}
    </div>
    <div class="fieldWrapper">
      {{ form.urgent.as_field_group }}
    </div>

By default Django uses the `"django/forms/field.html"` template which is designed for use with the default `"django/forms/div.html"` form style.

The default template can be customized by setting `field_template_name` in your project-level `FORM_RENDERER`:

    from django.forms.renderers import TemplatesSetting

    class CustomFormRenderer(TemplatesSetting):
        field_template_name = "field_snippet.html"

… or on a single field:

    class MyForm(forms.Form):
        subject = forms.CharField(template_name="my_custom_template.html")
        ...

… or on a per-request basis by calling `BoundField.render()` and supplying a template name:

    def index(request):
        form = ContactForm()
        subject = form["subject"]
        context = {"subject": subject.render("my_custom_template.html")}
        return render(request, "index.html", context)

### Rendering fields manually

More fine grained control over field rendering is also possible. Likely this will be in a custom field template, to allow the template to be written once and reused for each field. However, it can also be directly accessed from the field attribute on the form. For example:

    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="{{ form.subject.id_for_label }}">Email subject:</label>
        {{ form.subject }}
    </div>
    <div class="fieldWrapper">
        {{ form.message.errors }}
        <label for="{{ form.message.id_for_label }}">Your message:</label>
        {{ form.message }}
    </div>
    <div class="fieldWrapper">
        {{ form.contact_email.errors }}
        <label for="{{ form.contact_email.id_for_label }}">Your email address:</label>
        {{ form.contact_email }}
    </div>
    <div class="fieldWrapper">
        {{ form.urgent.errors }}
        <label for="{{ form.urgent.id_for_label }}">Urgent reply needed?</label>
        {{ form.urgent }}
    </div>

Complete `<label>` elements can also be generated using the `label_tag()`. For example:

    <div class="fieldWrapper">
        {{ form.subject.errors }}
        {{ form.subject.label_tag }}
        {{ form.subject }}
    </div>

#### Rendering form error messages

The price of this flexibility is a bit more work. Until now we haven’t had to worry about how to display form errors, because that’s taken care of for us. In this example we have had to make sure we take care of any errors for each field and any errors for the form as a whole. Note `{{ form.non_field_errors }}` at the top of the form and the template lookup for errors on each field.

Using `{{ form.name_of_field.errors }}` displays a list of form errors, rendered as an unordered list. This might look like:

    <ul class="errorlist">
        <li>Contact email is required.</li>
    </ul>

The list has a CSS class of `errorlist` to allow you to style its appearance. If you wish to further customize the display of errors you can do so by looping over them:

    {% if form.subject.errors %}
        <ol>
        {% for error in form.subject.errors %}
            <li><strong>{{ error|escape }}</strong></li>
        {% endfor %}
        </ol>
    {% endif %}

Non-field errors (and/or hidden field errors that are rendered at the top of the form when using helpers like `form.as_p()`) will be rendered with an additional class of `nonfield` to help distinguish them from field-specific errors. For example, `{{ form.non_field_errors }}` would look like:

    <ul class="errorlist nonfield">
        <li>Generic validation error</li>
    </ul>

See The Forms API for more on errors, styling, and working with form attributes in templates.

### Looping over the form’s fields

If you’re using the same HTML for each of your form fields, you can reduce duplicate code by looping through each field in turn using a `{% for %}` loop:

    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }} {{ field }}
            {% if field.help_text %}
              <p class="help" id="{{ field.auto_id }}_helptext">
                {{ field.help_text|safe }}
              </p>
            {% endif %}
        </div>
    {% endfor %}

Useful attributes on `{{ field }}` include:

`{{ field.errors }}`

  Outputs a `<ul class="errorlist">` containing any validation errors corresponding to this field. You can customize the presentation of the errors with a `{% for error in field.errors %}` loop. In this case, each object in the loop is a string containing the error message.

`{{ field.field }}`

  The `Field` instance from the form class that this `BoundField` wraps. You can use it to access `Field` attributes, e.g. `{{ char_field.field.max_length }}`.

`{{ field.help_text }}`

  Any help text that has been associated with the field.

`{{ field.html_name }}`

  The name of the field that will be used in the input element’s name field. This takes the form prefix into account, if it has been set.

`{{ field.id_for_label }}`

  The ID that will be used for this field (`id_contact_email` in the example above). If you are constructing the label manually, you may want to use this in lieu of `label_tag`. It’s also useful, for example, if you have some inline JavaScript and want to avoid hardcoding the field’s ID.

`{{ field.is_hidden }}`

  This attribute is `True` if the form field is a hidden field and `False` otherwise. It’s not particularly useful as a template variable, but could be useful in conditional tests such as:

    {% if field.is_hidden %}
       {# Do something special #}
    {% endif %}

`{{ field.label }}`

  The label of the field, e.g. `Contact email`.

`{{ field.label_tag }}`

  The field’s label wrapped in the appropriate HTML `<label>` tag. This includes the form’s `label_suffix`. For example, the default `label_suffix` is a colon:

      <label for="id_contact_email">Contact email:</label>

`{{ field.legend_tag }}`

  Similar to `field.label_tag` but uses a `<legend>` tag in place of `<label>`, for widgets with multiple inputs wrapped in a `<fieldset>`.

`{{ field.use_fieldset }}`

  This attribute is `True` if the form field’s widget contains multiple inputs that should be semantically grouped in a `<fieldset>` with a `<legend>` to improve accessibility. An example use in a template:

    {% if field.use_fieldset %}
      <fieldset>
      {% if field.label %}{{ field.legend_tag }}{% endif %}
    {% else %}
      {% if field.label %}{{ field.label_tag }}{% endif %}
    {% endif %}
    {{ field }}
    {% if field.use_fieldset %}</fieldset>{% endif %}

`{{ field.value }}`

  The value of the field. e.g `someone@example.com`.

For a complete list of attributes and methods, see the reference guide for `BoundField`.

#### Looping over hidden and visible fields

If you’re manually laying out a form in a template, as opposed to relying on Django’s default form layout, you might want to treat `<input type="hidden">` fields differently from non-hidden fields. For example, because hidden fields don’t display anything, putting error messages “next to” the field could cause confusion for your users – so errors for those fields should be handled differently.

Django provides two methods on a form that allow you to loop over the hidden and visible fields independently: `hidden_fields()` and `visible_fields()`. Here’s a modification of an earlier example that uses these two methods:

    {# Include the hidden fields #}
    {% for hidden in form.hidden_fields %}
    {{ hidden }}
    {% endfor %}
    {# Include the visible fields #}
    {% for field in form.visible_fields %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }} {{ field }}
        </div>
    {% endfor %}

This example does not handle any errors in the hidden fields. Usually, an error in a hidden field is a sign of form tampering, since normal form interaction won’t alter them. However, you could easily insert some error displays for those form errors, as well.

## Further topics

This covers the basics, but forms can do a whole lot more:

- Formsets
  - Using initial data with a formset
  - Limiting the maximum number of forms
  - Limiting the maximum number of instantiated forms
  - Formset validation
  - Validating the number of forms in a formset
  - Dealing with ordering and deletion of forms
  - Adding additional fields to a formset
  - Passing custom parameters to formset forms
  - Customizing a formset’s prefix
  - Using a formset in views and templates
- Creating forms from models
  - `ModelForm`
  - Model formsets
  - Inline formsets
- Form Assets (the `Media` class)
  - Assets as a static definition
  - `Media` as a dynamic property
  - Paths in asset definitions
  - `Media` objects
  - `Media` on Forms

더 보기

The Forms Reference

  Covers the full API reference, including form fields, form widgets, and form and field validation.

django-formtools

  Provides additional form utilities, such as form previews and wizards (documentation).