Django Template to Render Again When Swiping Back on Phone

Django Tutorial Part 9: Working with forms

  • Previous
  • Overview: Django
  • Next

In this tutorial, nosotros'll evidence y'all how to work with HTML Forms in Django, and, in particular, the easiest style to write forms to create, update, and delete model instances. As office of this demonstration, nosotros'll extend the LocalLibrary website so that librarians can renew books, and create, update, and delete authors using our own forms (rather than using the admin awarding).

Overview

An HTML Form is a group of one or more fields/widgets on a web page, which tin can be used to collect data from users for submission to a server. Forms are a flexible mechanism for collecting user input considering there are suitable widgets for entering many unlike types of data, including text boxes, checkboxes, radio buttons, date pickers and and then on. Forms are also a relatively secure way of sharing data with the server, as they allow us to send data in Mail service requests with cross-site request forgery protection.

While nosotros haven't created any forms in this tutorial and so far, we've already encountered them in the Django Admin site — for case, the screenshot beneath shows a form for editing one of our Book models, comprised of a number of option lists and text editors.

Admin Site - Book Add

Working with forms can be complicated! Developers demand to write HTML for the class, validate and properly sanitize entered information on the server (and possibly also in the browser), repost the class with mistake messages to inform users of any invalid fields, handle the information when it has successfully been submitted, and finally reply to the user in some way to signal success. Django Forms take a lot of the work out of all these steps, by providing a framework that lets y'all define forms and their fields programmatically, and then utilise these objects to both generate the form HTML code and handle much of the validation and user interaction.

In this tutorial, nosotros're going to show yous a few of the ways you can create and work with forms, and in particular, how the generic editing views can significantly reduce the corporeality of work y'all demand to do to create forms to manipulate your models. Forth the way, nosotros'll extend our LocalLibrary awarding by calculation a form to allow librarians to renew library books, and we'll create pages to create, edit and delete books and authors (reproducing a basic version of the grade shown higher up for editing books).

HTML Forms

Outset, a cursory overview of HTML Forms. Consider a simple HTML class, with a single text field for entering the name of some "team", and its associated label:

Simple name field example in HTML form

The form is divers in HTML as a collection of elements inside <form>...</form> tags, containing at least ane input chemical element of type="submit".

                                                                                    <form                      action                                              =                        "/team_name_url/"                                            method                                              =                        "post"                                            >                                                                                      <label                      for                                              =                        "team_name"                                            >                    Enter name:                                                                  </characterization                      >                                                                                      <input                      id                                              =                        "team_name"                                            type                                              =                        "text"                                            name                                              =                        "name_field"                                            value                                              =                        "Default proper noun for team."                                            >                                                                                      <input                      type                                              =                        "submit"                                            value                                              =                        "OK"                                            >                                                                                      </form                      >                                                      

While here we merely have 1 text field for entering the team name, a form may take whatsoever number of other input elements and their associated labels. The field's type attribute defines what sort of widget will be displayed. The proper noun and id of the field are used to identify the field in JavaScript/CSS/HTML, while value defines the initial value for the field when it is first displayed. The matching team label is specified using the label tag (encounter "Enter name" in a higher place), with a for field containing the id value of the associated input.

The submit input will be displayed equally a push button by default. This tin can be pressed to upload the information in all the other input elements in the form to the server (in this case, just the team_name field). The course attributes define the HTTP method used to send the information and the destination of the data on the server (action):

  • action: The resources/URL where data is to exist sent for processing when the form is submitted. If this is not set (or set to an empty string), then the class will be submitted back to the current page URL.
  • method: The HTTP method used to send the data: post or get.
    • The POST method should ever exist used if the data is going to effect in a change to the server's database, because information technology can be fabricated more resistant to cross-site forgery request attacks.
    • The GET method should merely be used for forms that don't change user data (for example, a search class). Information technology is recommended for when y'all want to be able to bookmark or share the URL.

The role of the server is first to render the initial class country — either containing blank fields or pre-populated with initial values. Later the user presses the submit button, the server will receive the form data with values from the web browser and must validate the data. If the form contains invalid data, the server should display the form again, this time with user-entered data in "valid" fields and letters to draw the problem for the invalid fields. Once the server gets a request with all valid form data, it tin can perform an advisable activity (such as: saving the data, returning the result of a search, uploading a file, etc.) and and then notify the user.

As you can imagine, creating the HTML, validating the returned data, re-displaying the entered data with error reports if needed, and performing the desired functioning on valid data tin can all take quite a lot of effort to "get right". Django makes this a lot easier past taking away some of the heavy lifting and repetitive code!

Django form handling procedure

Django's course handling uses all of the same techniques that we learned about in previous tutorials (for displaying information about our models): the view gets a request, performs any deportment required including reading data from the models, then generates and returns an HTML folio (from a template, into which we pass a context containing the data to be displayed). What makes things more complicated is that the server likewise needs to exist able to procedure data provided by the user, and redisplay the folio if there are any errors.

A process flowchart of how Django handles grade requests is shown beneath, starting with a asking for a page containing a class (shown in green).

Updated form handling process doc.

Based on the diagram higher up, the main things that Django's form handling does are:

  1. Display the default form the get-go time it is requested by the user.
    • The form may contain bare fields if you're creating a new record, or information technology may be pre-populated with initial values (for example, if you are irresolute a record, or have useful default initial values).
    • The class is referred to as unbound at this point, because it isn't associated with any user-entered information (though it may accept initial values).
  2. Receive data from a submit asking and bind it to the course.
    • Binding data to the form means that the user-entered data and any errors are available when we demand to redisplay the class.
  3. Clean and validate the information.
    • Cleaning the information performs sanitization of the input fields, such as removing invalid characters that might be used to send malicious content to the server, and converts them into consistent Python types.
    • Validation checks that the values are advisable for the field (for case, that they are in the correct date range, aren't too short or too long, etc.)
  4. If any data is invalid, re-display the grade, this time with any user populated values and mistake messages for the trouble fields.
  5. If all data is valid, perform required actions (such equally salvage the data, send an email, return the result of a search, upload a file, and so on).
  6. Once all actions are consummate, redirect the user to another page.

Django provides a number of tools and approaches to assist you lot with the tasks detailed in a higher place. The most fundamental is the Form class, which simplifies both generation of grade HTML and data cleaning/validation. In the adjacent department, nosotros depict how forms work using the practical example of a page to allow librarians to renew books.

Notation: Understanding how Course is used will help you lot when we discuss Django's more "high level" form framework classes.

Renew-volume form using a Form and function view

Adjacent, nosotros're going to add a page to let librarians to renew borrowed books. To do this we'll create a form that allows users to enter a appointment value. We'll seed the field with an initial value 3 weeks from the current date (the normal borrowing period), and add together some validation to ensure that the librarian can't enter a date in the past or a date too far in the future. When a valid date has been entered, we'll write it to the electric current record'due south BookInstance.due_back field.

The example will utilize a role-based view and a Form form. The following sections explicate how forms work, and the changes you need to make to our ongoing LocalLibrary project.

Course

The Course class is the heart of Django'south class treatment system. It specifies the fields in the class, their layout, display widgets, labels, initial values, valid values, and (once validated) the error letters associated with invalid fields. The course besides provides methods for rendering itself in templates using predefined formats (tables, lists, etc.) or for getting the value of any element (enabling fine-grained manual rendering).

Declaring a Form

The declaration syntax for a Form is very like to that for declaring a Model, and shares the same field types (and some similar parameters). This makes sense because in both cases we demand to ensure that each field handles the right types of information, is constrained to valid data, and has a description for brandish/documentation.

Form data is stored in an awarding's forms.py file, inside the awarding directory. Create and open the file locallibrary/itemize/forms.py. To create a Form, we import the forms library, derive from the Class class, and declare the grade'southward fields. A very basic form class for our library book renewal form is shown below — add this to your new file:

                                      from                    django                    import                    forms                    class                    RenewBookForm                    (forms.Form)                    :                    renewal_date                    =                    forms.DateField(help_text=                    "Enter a date between now and 4 weeks (default 3)."                    )                                  

Form fields

In this case, we take a single DateField for entering the renewal date that volition render in HTML with a blank value, the default label "Renewal engagement:", and some helpful usage text: "Enter a engagement between now and 4 weeks (default iii weeks)." Equally none of the other optional arguments are specified the field volition have dates using the input_formats: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (ten/25/16), and volition be rendered using the default widget: DateInput.

There are many other types of form fields, which you lot will largely recognize from their similarity to the equivalent model field classes: BooleanField, CharField, ChoiceField, TypedChoiceField, DateField, DateTimeField, DecimalField, DurationField, EmailField, FileField, FilePathField, FloatField, ImageField, IntegerField, GenericIPAddressField, MultipleChoiceField, TypedMultipleChoiceField, NullBooleanField, RegexField, SlugField, TimeField, URLField, UUIDField, ComboField, MultiValueField, SplitDateTimeField, ModelMultipleChoiceField, ModelChoiceField.

The arguments that are common to most fields are listed beneath (these have sensible default values):

  • required: If True, the field may not exist left blank or given a None value. Fields are required by default, so you would set up required=False to allow blank values in the grade.
  • label: The label to employ when rendering the field in HTML. If a label is not specified, Django will create ane from the field proper name past capitalizing the first alphabetic character and replacing underscores with spaces (eastward.g. Renewal date).
  • label_suffix: By default, a colon is displayed after the label (e.grand. Renewal date​:). This argument allows you to specify a different suffix containing other character(due south).
  • initial: The initial value for the field when the form is displayed.
  • widget: The display widget to use.
  • help_text (as seen in the instance to a higher place): Additional text that tin exist displayed in forms to explain how to use the field.
  • error_messages: A listing of error letters for the field. Yous tin override these with your own messages if needed.
  • validators: A list of functions that will be called on the field when it is validated.
  • localize: Enables the localization of form data input (come across link for more information).
  • disabled: The field is displayed simply its value cannot exist edited if this is True. The default is Fake.

Validation

Django provides numerous places where you tin can validate your data. The easiest way to validate a unmarried field is to override the method clean_<fieldname>() for the field you want to check. Then for instance, we can validate that entered renewal_date values are between now and iv weeks by implementing clean_renewal_date() as shown below.

Update your forms.py file so information technology looks similar this:

                                      import                    datetime                    from                    django                    import                    forms                    from                    django.core.exceptions                    import                    ValidationError                    from                    django.utils.translation                    import                    gettext_lazy                    as                    _                    class                    RenewBookForm                    (forms.Form)                    :                    renewal_date                    =                    forms.DateField(help_text=                    "Enter a date between now and 4 weeks (default 3)."                    )                    def                    clean_renewal_date                    (self)                    :                    data                    =                    cocky.cleaned_data[                    'renewal_date'                    ]                    # Check if a date is not in the past.                    if                    data                    <                    datetime.date.today(                    )                    :                    enhance                    ValidationError(_(                    'Invalid date - renewal in by'                    )                    )                    # Check if a engagement is in the immune range (+iv weeks from today).                    if                    information                    >                    datetime.date.today(                    )                    +                    datetime.timedelta(weeks=                    4                    )                    :                    raise                    ValidationError(_(                    'Invalid date - renewal more than iv weeks alee'                    )                    )                    # Remember to always render the cleaned data.                    return                    information                                  

In that location are ii important things to notation. The first is that we get our information using cocky.cleaned_data['renewal_date'] and that we return this data whether or not nosotros change it at the cease of the function. This step gets u.s. the information "cleaned" and sanitized of potentially unsafe input using the default validators, and converted into the correct standard type for the data (in this case a Python datetime.datetime object).

The second bespeak is that if a value falls outside our range we raise a ValidationError, specifying the mistake text that we desire to display in the form if an invalid value is entered. The example above likewise wraps this text in one of Django'south translation functions, gettext_lazy() (imported as _()), which is good practice if you lot desire to interpret your site later.

Note: In that location are numerous other methods and examples for validating forms in Form and field validation (Django docs). For case, in cases where you have multiple fields that depend on each other, you can override the Form.make clean() function and once again raise a ValidationError.

That'due south all nosotros need for the form in this case!

URL configuration

Before nosotros create our view, let's add a URL configuration for the renew-books page. Re-create the following configuration to the bottom of locallibrary/catalog/urls.py:

                  urlpatterns                    +=                    [                    path(                    'volume/<uuid:pk>/renew/'                    ,                    views.renew_book_librarian,                    name=                    'renew-book-librarian'                    )                    ,                    ]                                  

The URL configuration will redirect URLs with the format /itemize/book/<bookinstance_id>/renew/ to the function named renew_book_librarian() in views.py, and ship the BookInstance id as the parameter named pk. The pattern only matches if pk is a correctly formatted uuid.

Note: We can proper noun our captured URL data "pk" anything nosotros like, considering nosotros have consummate control over the view function (we're not using a generic detail view class that expects parameters with a certain proper name). However, pk short for "principal key", is a reasonable convention to utilise!

View

Equally discussed in the Django grade handling process above, the view has to render the default form when it is start called and and so either re-render information technology with error messages if the information is invalid, or process the data and redirect to a new page if the data is valid. In order to perform these different deportment, the view has to be able to know whether it is being called for the start time to return the default form, or a subsequent time to validate data.

For forms that use a POST asking to submit data to the server, the most common pattern is for the view to test against the POST request type (if request.method == 'Post':) to identify class validation requests and Become (using an else condition) to identify the initial course creation request. If y'all want to submit your information using a Become asking, then a typical approach for identifying whether this is the first or subsequent view invocation is to read the course information (east.grand. to read a hidden value in the form).

The volume renewal process will be writing to our database, so, past convention, nosotros utilize the POST request approach. The code fragment beneath shows the (very standard) pattern for this sort of part view.

                                      import                    datetime                    from                    django.shortcuts                    import                    render,                    get_object_or_404                    from                    django.http                    import                    HttpResponseRedirect                    from                    django.urls                    import                    reverse                    from                    catalog.forms                    import                    RenewBookForm                    def                    renew_book_librarian                    (asking,                    pk)                    :                    book_instance                    =                    get_object_or_404(BookInstance,                    pk=pk)                    # If this is a Post request then procedure the Grade data                    if                    request.method                    ==                    'Mail service'                    :                    # Create a form instance and populate information technology with data from the asking (binding):                    form                    =                    RenewBookForm(asking.Post)                    # Bank check if the form is valid:                    if                    grade.is_valid(                    )                    :                    # process the data in class.cleaned_data as required (hither nosotros just write it to the model due_back field)                    book_instance.due_back                    =                    form.cleaned_data[                    'renewal_date'                    ]                    book_instance.save(                    )                    # redirect to a new URL:                    return                    HttpResponseRedirect(reverse(                    'all-borrowed'                    )                    )                    # If this is a Go (or whatever other method) create the default form.                    else                    :                    proposed_renewal_date                    =                    datetime.date.today(                    )                    +                    datetime.timedelta(weeks=                    3                    )                    form                    =                    RenewBookForm(initial=                    {                    'renewal_date'                    :                    proposed_renewal_date}                    )                    context                    =                    {                    'form'                    :                    form,                    'book_instance'                    :                    book_instance,                    }                    return                    render(request,                    'catalog/book_renew_librarian.html'                    ,                    context)                                  

Kickoff, we import our grade (RenewBookForm) and a number of other useful objects/methods used in the torso of the view function:

  • get_object_or_404(): Returns a specified object from a model based on its master key value, and raises an Http404 exception (not found) if the record does non be.
  • HttpResponseRedirect: This creates a redirect to a specified URL (HTTP status code 302).
  • reverse(): This generates a URL from a URL configuration proper noun and a prepare of arguments. It is the Python equivalent of the url tag that we've been using in our templates.
  • datetime: A Python library for manipulating dates and times.

In the view, nosotros first use the pk argument in get_object_or_404() to get the current BookInstance (if this does non be, the view will immediately exit and the page will display a "not found" mistake). If this is not a POST request (handled by the else clause) then we create the default form passing in an initial value for the renewal_date field, 3 weeks from the current date.

                  book_instance                    =                    get_object_or_404(BookInstance,                    pk=pk)                    # If this is a GET (or whatever other method) create the default course                    else                    :                    proposed_renewal_date                    =                    datetime.date.today(                    )                    +                    datetime.timedelta(weeks=                    3                    )                    form                    =                    RenewBookForm(initial=                    {                    'renewal_date'                    :                    proposed_renewal_date}                    )                    context                    =                    {                    'form'                    :                    form,                    'book_instance'                    :                    book_instance,                    }                    return                    return(request,                    'itemize/book_renew_librarian.html'                    ,                    context)                                  

After creating the form, we call render() to create the HTML page, specifying the template and a context that contains our grade. In this case, the context also contains our BookInstance, which we'll use in the template to provide information about the book we're renewing.

However, if this is a POST asking, then we create our form object and populate it with information from the asking. This process is called "binding" and allows us to validate the form.

We then check if the grade is valid, which runs all the validation code on all of the fields — including both the generic code to check that our date field is actually a valid appointment and our specific form's clean_renewal_date() office to check the engagement is in the right range.

                  book_instance                    =                    get_object_or_404(BookInstance,                    pk=pk)                    # If this is a POST request then procedure the Grade data                    if                    asking.method                    ==                    'POST'                    :                    # Create a form example and populate information technology with data from the asking (binding):                    class                    =                    RenewBookForm(request.Postal service)                    # Check if the course is valid:                    if                    form.is_valid(                    )                    :                    # process the information in course.cleaned_data as required (here we just write it to the model due_back field)                    book_instance.due_back                    =                    class.cleaned_data[                    'renewal_date'                    ]                    book_instance.save(                    )                    # redirect to a new URL:                    return                    HttpResponseRedirect(opposite(                    'all-borrowed'                    )                    )                    context                    =                    {                    'class'                    :                    form,                    'book_instance'                    :                    book_instance,                    }                    return                    render(asking,                    'catalog/book_renew_librarian.html'                    ,                    context)                                  

If the form is not valid we phone call return() again, but this time the form value passed in the context will include error messages.

If the class is valid, then nosotros tin start to utilize the data, accessing it through the course.cleaned_data attribute (e.g. data = form.cleaned_data['renewal_date']). Here, we just save the information into the due_back value of the associated BookInstance object.

Alarm: While you can likewise access the form data directly through the request (for case, request.POST['renewal_date'] or asking.Get['renewal_date'] if using a Go asking), this is Not recommended. The cleaned data is sanitized, validated, and converted into Python-friendly types.

The final footstep in the grade-handling part of the view is to redirect to another page, ordinarily a "success" page. In this case, we employ HttpResponseRedirect and reverse() to redirect to the view named 'all-borrowed' (this was created as the "claiming" in Django Tutorial Part 8: User authentication and permissions). If yous didn't create that folio consider redirecting to the home folio at URL '/').

That'due south everything needed for the form treatment itself, merely we withal demand to restrict access to the view to only logged-in librarians who accept permission to renew books. We use @login_required to crave that the user is logged in, and the @permission_required function decorator with our existing can_mark_returned permission to allow access (decorators are processed in order). Annotation that nosotros probably should have created a new permission setting in BookInstance ("can_renew"), simply we volition reuse the existing one to keep the example uncomplicated.

The final view is therefore as shown below. Delight copy this into the lesser of locallibrary/itemize/views.py.

                                      import                    datetime                    from                    django.contrib.auth.decorators                    import                    login_required,                    permission_required                    from                    django.shortcuts                    import                    get_object_or_404                    from                    django.http                    import                    HttpResponseRedirect                    from                    django.urls                    import                    opposite                    from                    itemize.forms                    import                    RenewBookForm                    @login_required                    @permission_required                    (                    'itemize.can_mark_returned'                    ,                    raise_exception=                    Truthful                    )                    def                    renew_book_librarian                    (asking,                    pk)                    :                    """View function for renewing a specific BookInstance by librarian."""                    book_instance                    =                    get_object_or_404(BookInstance,                    pk=pk)                    # If this is a Mail request and so process the Form data                    if                    request.method                    ==                    'POST'                    :                    # Create a form instance and populate it with data from the request (bounden):                    course                    =                    RenewBookForm(request.Mail service)                    # Cheque if the form is valid:                    if                    form.is_valid(                    )                    :                    # process the data in form.cleaned_data as required (here we just write it to the model due_back field)                    book_instance.due_back                    =                    form.cleaned_data[                    'renewal_date'                    ]                    book_instance.relieve(                    )                    # redirect to a new URL:                    render                    HttpResponseRedirect(reverse(                    'all-borrowed'                    )                    )                    # If this is a Get (or any other method) create the default form.                    else                    :                    proposed_renewal_date                    =                    datetime.appointment.today(                    )                    +                    datetime.timedelta(weeks=                    3                    )                    form                    =                    RenewBookForm(initial=                    {                    'renewal_date'                    :                    proposed_renewal_date}                    )                    context                    =                    {                    'form'                    :                    form,                    'book_instance'                    :                    book_instance,                    }                    return                    render(request,                    'itemize/book_renew_librarian.html'                    ,                    context)                                  

The template

Create the template referenced in the view (/catalog/templates/catalog/book_renew_librarian.html) and re-create the lawmaking below into it:

                  {% extends "base_generic.html" %}  {% block content %}                                                                  <h1                      >                    Renew: {{ book_instance.book.title }}                                              </h1                      >                                                                                      <p                      >                    Borrower: {{ book_instance.borrower }}                                              </p                      >                                        <p{% if book_instance.is_overdue %} class="text-danger"{% endif %}>Due date: {{ book_instance.due_back }}                                              </p                      >                                                                                      <class                      action                                              =                        "                        "                                            method                                              =                        "post"                                            >                                        {% csrf_token %}                                                                  <table                      >                                        {{ form.as_table }}                                                                  </tabular array                      >                                                                                      <input                      type                                              =                        "submit"                                            value                                              =                        "Submit"                                            >                                                                                      </form                      >                                        {% endblock %}                                  

Most of this will exist completely familiar from previous tutorials.

Nosotros extend the base template and and then redefine the content cake. We are able to reference {{ book_instance }} (and its variables) because it was passed into the context object in the return() function, and we use these to list the book championship, borrower, and the original due date.

The form code is relatively uncomplicated. Starting time, we declare the grade tags, specifying where the form is to be submitted (activeness) and the method for submitting the data (in this case an "HTTP POST") — if you recall the HTML Forms overview at the top of the folio, an empty action as shown, means that the form data will exist posted back to the current URL of the page (which is what we want). Inside the tags, nosotros define the submit input, which a user can press to submit the data. The {% csrf_token %} added just inside the course tags is role of Django's cantankerous-site forgery protection.

Annotation: Add the {% csrf_token %} to every Django template you create that uses Post to submit data. This will reduce the risk of forms being hijacked by malicious users.

All that's left is the {{ form }} template variable, which we passed to the template in the context dictionary. Perhaps unsurprisingly, when used as shown this provides the default rendering of all the form fields, including their labels, widgets, and help text — the rendering is as shown below:

                                                                                    <tr                      >                                                                                      <th                      >                                                                                      <characterization                      for                                              =                        "id_renewal_date"                                            >                    Renewal date:                                              </label                      >                                                                                      </thursday                      >                                                                                      <td                      >                                                                                      <input                      id                                              =                        "id_renewal_date"                                            name                                              =                        "renewal_date"                                            type                                              =                        "text"                                            value                                              =                        "2016-11-08"                                            required                      >                                                                                      <br                      >                                                                                      <bridge                      class                                              =                        "helptext"                                            >                    Enter engagement between now and iv weeks (default iii weeks).                                              </span                      >                                                                                      </td                      >                                                                                      </tr                      >                                                      

Notation: It is perhaps non obvious considering nosotros only have one field, only, by default, every field is divers in its ain table row. This same rendering is provided if you reference the template variable {{ grade.as_table }}.

If you were to enter an invalid date, you'd additionally get a list of the errors rendered on the page (see errorlist below).

                                                                                    <tr                      >                                                                                      <thursday                      >                                                                                      <characterization                      for                                              =                        "id_renewal_date"                                            >                    Renewal date:                                              </label                      >                                                                                      </th                      >                                                                                      <td                      >                                                                                      <ul                      class                                              =                        "errorlist"                                            >                                                                                      <li                      >                    Invalid date - renewal in past                                              </li                      >                                                                                      </ul                      >                                                                                      <input                      id                                              =                        "id_renewal_date"                                            proper noun                                              =                        "renewal_date"                                            type                                              =                        "text"                                            value                                              =                        "2015-11-08"                                            required                      >                                                                                      <br                      >                                                                                      <span                      class                                              =                        "helptext"                                            >                    Enter engagement between now and iv weeks (default iii weeks).                                              </span                      >                                                                                      </td                      >                                                                                      </tr                      >                                                      

Other ways of using form template variable

Using {{ form.as_table }} as shown above, each field is rendered as a tabular array row. You tin also render each field as a list item (using {{ grade.as_ul }} ) or as a paragraph (using {{ grade.as_p }}).

It is also possible to accept consummate control over the rendering of each part of the form, by indexing its properties using dot notation. And then, for instance, we can access a number of split items for our renewal_date field:

  • {{ grade.renewal_date }}: The whole field.
  • {{ form.renewal_date.errors }}: The list of errors.
  • {{ form.renewal_date.id_for_label }}: The id of the label.
  • {{ form.renewal_date.help_text }}: The field help text.

For more examples of how to manually render forms in templates and dynamically loop over template fields, run into Working with forms > Rendering fields manually (Django docs).

Testing the page

If yous accustomed the "claiming" in Django Tutorial Part 8: User hallmark and permissions you'll have a list of all books on loan in the library, which is merely visible to library staff. We can add a link to our renew folio next to each item using the template code below.

                  {% if perms.catalog.can_mark_returned %}-                                                                  <a                      href                                              =                        "{% url                        'renew-volume-librarian'                        bookinst.id %}"                                            >                    Renew                                              </a                      >                                        {% endif %}                                  

Note: Remember that your test login volition demand to accept the permission "catalog.can_mark_returned" in order to access the renew book page (perhaps use your superuser account).

You tin can alternatively manually construct a exam URL similar this — http://127.0.0.1:8000/catalog/book/<bookinstance_id>/renew/ (a valid bookinstance_id can be obtained past navigating to a volume detail folio in your library, and copying the id field).

What does information technology look like?

If yous are successful, the default grade volition look similar this:

The grade with an invalid value entered will expect like this:

The list of all books with renew links will look like this:

ModelForms

Creating a Form class using the approach described above is very flexible, allowing you to create whatever sort of form folio you like and acquaintance information technology with any model or models.

However, if you just need a form to map the fields of a single model then your model volition already define nearly of the information that you lot need in your form: fields, labels, aid text and so on. Rather than recreating the model definitions in your form, it is easier to employ the ModelForm helper form to create the course from your model. This ModelForm can and then be used inside your views in exactly the aforementioned manner as an ordinary Course.

A basic ModelForm containing the same field every bit our original RenewBookForm is shown below. All you need to exercise to create the form is add class Meta with the associated model (BookInstance) and a list of the model fields to include in the form.

                                      from                    django.forms                    import                    ModelForm                    from                    catalog.models                    import                    BookInstance                    class                    RenewBookModelForm                    (ModelForm)                    :                    class                    Meta                    :                    model                    =                    BookInstance         fields                    =                    [                    'due_back'                    ]                                  

Notation: You can besides include all fields in the form using fields = '__all__', or you can utilize exclude (instead of fields) to specify the fields not to include from the model).

Neither arroyo is recommended because new fields added to the model are then automatically included in the form (without the developer necessarily considering possible security implications).

Annotation: This might not look all that much simpler than but using a Course (and information technology isn't in this case, because we just have one field). Still, if you have a lot of fields, it can reduce the amount of code quite significantly!

The residue of the information comes from the model field definitions (e.g. labels, widgets, assistance text, error messages). If these aren't quite right, and so we can override them in our form Meta, specifying a dictionary containing the field to modify and its new value. For case, in this form, we might want a label for our field of "Renewal date" (rather than the default based on the field name: Due Back), and we likewise want our help text to be specific to this use case. The Meta below shows y'all how to override these fields, and yous tin can similarly set widgets and error_messages if the defaults aren't sufficient.

                                      class                    Meta                    :                    model                    =                    BookInstance     fields                    =                    [                    'due_back'                    ]                    labels                    =                    {                    'due_back'                    :                    _(                    'New renewal date'                    )                    }                    help_texts                    =                    {                    'due_back'                    :                    _(                    'Enter a date betwixt now and 4 weeks (default 3).'                    )                    }                                  

To add together validation you can employ the aforementioned approach every bit for a normal Class — you define a office named clean_<field_name>() and heighten ValidationError exceptions for invalid values. The only difference with respect to our original course is that the model field is named due_back and not "renewal_date". This alter is necessary since the corresponding field in BookInstance is called due_back.

                                      from                    django.forms                    import                    ModelForm                    from                    catalog.models                    import                    BookInstance                    course                    RenewBookModelForm                    (ModelForm)                    :                    def                    clean_due_back                    (cocky)                    :                    data                    =                    self.cleaned_data[                    'due_back'                    ]                    # Check if a engagement is not in the past.                    if                    data                    <                    datetime.date.today(                    )                    :                    raise                    ValidationError(_(                    'Invalid date - renewal in past'                    )                    )                    # Bank check if a date is in the allowed range (+iv weeks from today).                    if                    data                    >                    datetime.appointment.today(                    )                    +                    datetime.timedelta(weeks=                    4                    )                    :                    raise                    ValidationError(_(                    'Invalid date - renewal more than four weeks ahead'                    )                    )                    # Remember to always return the cleaned data.                    render                    data                    course                    Meta                    :                    model                    =                    BookInstance         fields                    =                    [                    'due_back'                    ]                    labels                    =                    {                    'due_back'                    :                    _(                    'Renewal date'                    )                    }                    help_texts                    =                    {                    'due_back'                    :                    _(                    'Enter a date betwixt now and 4 weeks (default 3).'                    )                    }                                  

The form RenewBookModelForm above is now functionally equivalent to our original RenewBookForm. You could import and employ information technology wherever you lot currently use RenewBookForm every bit long every bit yous also update the respective form variable proper noun from renewal_date to due_back as in the 2d form declaration: RenewBookModelForm(initial={'due_back': proposed_renewal_date}.

Generic editing views

The grade handling algorithm we used in our office view example above represents an extremely common pattern in form editing views. Django abstracts much of this "boilerplate" for you, by creating generic editing views for creating, editing, and deleting views based on models. Non merely practise these handle the "view" behavior, but they automatically create the form class (a ModelForm) for you from the model.

Note: In addition to the editing views described here, there is besides a FormView class, which lies somewhere between our role view and the other generic views in terms of "flexibility" vs "coding effort". Using FormView, you notwithstanding need to create your Form, but you don't have to implement all of the standard course-handling patterns. Instead, you just have to provide an implementation of the function that will exist chosen once the submission is known to be valid.

In this department, nosotros're going to employ generic editing views to create pages to add functionality to create, edit, and delete Writer records from our library — effectively providing a basic reimplementation of parts of the Admin site (this could be useful if yous need to offering admin functionality in a more flexible style than can be provided by the admin site).

Views

Open up the views file (locallibrary/catalog/views.py) and append the following code cake to the lesser of information technology:

                                      from                    django.views.generic.edit                    import                    CreateView,                    UpdateView,                    DeleteView                    from                    django.urls                    import                    reverse_lazy                    from                    catalog.models                    import                    Author                    class                    AuthorCreate                    (CreateView)                    :                    model                    =                    Writer     fields                    =                    [                    'first_name'                    ,                    'last_name'                    ,                    'date_of_birth'                    ,                    'date_of_death'                    ]                    initial                    =                    {                    'date_of_death'                    :                    '11/06/2020'                    }                    course                    AuthorUpdate                    (UpdateView)                    :                    model                    =                    Writer     fields                    =                    '__all__'                    # Not recommended (potential security result if more than fields added)                    grade                    AuthorDelete                    (DeleteView)                    :                    model                    =                    Author     success_url                    =                    reverse_lazy(                    'authors'                    )                                  

Every bit you lot can see, to create, update, or delete the views you need to derive from CreateView, UpdateView, and DeleteView (respectively) and then define the associated model.

For the "create" and "update" cases you too need to specify the fields to display in the form (using the same syntax as for ModelForm). In this instance, nosotros show how to list them individually and the syntax to listing "all" fields. Yous tin also specify initial values for each of the fields using a dictionary of field_name/value pairs (hither we arbitrarily set the date of expiry for sit-in purposes — yous might want to remove that). By default, these views volition redirect on success to a folio displaying the newly created/edited model detail, which in our case will exist the author detail view nosotros created in a previous tutorial. You tin specify an alternative redirect location by explicitly declaring parameter success_url (every bit done for the AuthorDelete class).

The AuthorDelete class doesn't need to display any of the fields, so these don't need to be specified. You practise however demand to specify the success_url, because there is no obvious default value for Django to employ. In this case, we use the reverse_lazy() function to redirect to our author list later an writer has been deleted — reverse_lazy() is a lazily executed version of reverse(), used here because nosotros're providing a URL to a class-based view attribute.

Templates

The "create" and "update" views use the same template by default, which volition be named later on your model: model_name_form.html (you can alter the suffix to something other than _form using the template_name_suffix field in your view, for instance template_name_suffix = '_other_suffix')

Create the template file locallibrary/catalog/templates/itemize/author_form.html and copy in the text beneath.

                  {% extends "base_generic.html" %}  {% block content %}                                                                  <form                      action                                              =                        "                        "                                            method                                              =                        "post"                                            >                                        {% csrf_token %}                                                                  <table                      >                                        {{ form.as_table }}                                                                  </table                      >                                                                                      <input                      type                                              =                        "submit"                                            value                                              =                        "Submit"                                            >                                                                                      </course                      >                                        {% endblock %}                                  

This is similar to our previous forms and renders the fields using a tabular array. Note also how once again nosotros declare the {% csrf_token %} to ensure that our forms are resistant to CSRF attacks.

The "delete" view expects to discover a template named with the format model_name_confirm_delete.html (again, y'all can change the suffix using template_name_suffix in your view). Create the template file locallibrary/catalog/templates/catalog/author_confirm_delete.html and copy in the text below.

                  {% extends "base_generic.html" %}  {% block content %}                                                                  <h1                      >                    Delete Author                                              </h1                      >                                                                                      <p                      >                    Are yous sure you want to delete the author: {{ author }}?                                              </p                      >                                                                                      <form                      action                                              =                        "                        "                                            method                                              =                        "Postal service"                                            >                                        {% csrf_token %}                                                                  <input                      blazon                                              =                        "submit"                                            value                                              =                        "Yes, delete."                                            >                                                                                      </form                      >                                        {% endblock %}                                  

URL configurations

Open your URL configuration file (locallibrary/itemize/urls.py) and add the following configuration to the bottom of the file:

                  urlpatterns                    +=                    [                    path(                    'writer/create/'                    ,                    views.AuthorCreate.as_view(                    )                    ,                    proper name=                    'author-create'                    )                    ,                    path(                    'author/<int:pk>/update/'                    ,                    views.AuthorUpdate.as_view(                    )                    ,                    name=                    'writer-update'                    )                    ,                    path(                    'author/<int:pk>/delete/'                    ,                    views.AuthorDelete.as_view(                    )                    ,                    proper name=                    'writer-delete'                    )                    ,                    ]                                  

In that location is nothing particularly new here! You tin run across that the views are classes, and must hence be called via .as_view(), and you should be able to recognize the URL patterns in each instance. Nosotros must use pk as the proper noun for our captured main key value, as this is the parameter name expected past the view classes.

The author create, update, and delete pages are now prepare to test (we won't bother hooking them into the site sidebar in this case, although you lot can do so if you wish).

Note: Observant users will have noticed that we didn't do anything to prevent unauthorized users from accessing the pages! We leave that as an do for you (hint: y'all could use the PermissionRequiredMixin and either create a new permission or reuse our can_mark_returned permission).

Testing the page

Commencement, log in to the site with an account that has whatever permissions you decided are needed to access the author editing pages.

So navigate to the author create page, http://127.0.0.1:8000/catalog/author/create/, which should expect like the screenshot below.

Form Example: Create Author

Enter values for the fields and then printing Submit to salvage the author tape. You should now be taken to a detail view for your new author, with a URL of something like http://127.0.0.one:8000/catalog/author/10.

You can examination editing records by appending /update/ to the end of the item view URL (e.thousand. http://127.0.0.1:8000/catalog/author/10/update/) — we don't show a screenshot considering information technology looks only similar the "create" page!

Finally, we tin can delete the page by appending delete to the finish of the author detail-view URL (e.1000. http://127.0.0.1:8000/catalog/writer/ten/delete/). Django should display the delete page shown beneath. Printing "Yes, delete." to remove the tape and be taken to the list of all authors.

Challenge yourself

Create some forms to create, edit, and delete Volume records. Y'all can use exactly the same structure as for Authors. If your book_form.html template is but a copy-renamed version of the author_form.html template, then the new "create book" page will await like the screenshot below:

Summary

Creating and treatment forms tin can be a complicated process! Django makes it much easier by providing programmatic mechanisms to declare, render, and validate forms. Furthermore, Django provides generic form editing views that can do almost all the piece of work to define pages that can create, edit, and delete records associated with a unmarried model case.

At that place is a lot more that tin can be done with forms (check out our Encounter also list below), but you should at present empathize how to add bones forms and form-treatment code to your own websites.

See also

In this module

jonescuposer.blogspot.com

Source: https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms

0 Response to "Django Template to Render Again When Swiping Back on Phone"

ارسال یک نظر

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel