Django login form error

I make login/password form: model: class LoginForm(forms.Form): username = forms.CharField(max_length=100) password = forms.CharField(widget=forms.PasswordInput(render_value=False),max_length=100)

Because the form has no idea an error occurred.

When you construct the form here:

form=LoginForm()

You’re constructing it without passing it any information. It doesn’t know anything about the POST the user just did, or that the the login failed, or that the password was missing, or whatever the error was.

Here’s what my login forms look like:

class LoginForm(forms.Form):
    username = forms.CharField(max_length=255, required=True)
    password = forms.CharField(widget=forms.PasswordInput, required=True)

    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')
        user = authenticate(username=username, password=password)
        if not user or not user.is_active:
            raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
        return self.cleaned_data

    def login(self, request):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')
        user = authenticate(username=username, password=password)
        return user

We override the form’s clean method, so that if the form passes validation we can check the user’s credentials. We also put a login method on the form object itself, to make our view cleaner.

Next, in our view, we want to do this:

def login_view(request):
    form = LoginForm(request.POST or None)
    if request.POST and form.is_valid():
        user = form.login(request)
        if user:
            login(request, user)
            return HttpResponseRedirect("/n1.html")# Redirect to a success page.
    return render(request, 'enter.html', {'login_form': form })

We instantiate the form and hand it the request.POST to check against.

If we have a POST, we check if the form is valid. The form’s «clean» method will get called, and check the user credentials for us.

If the credentials fail, we raise an error, which we need to show in our template.

Errors raised by the form (but not attached to a field) are stored in non_field_errors, which can be displayed like so:

{% if form.non_field_errors %}
    <ul class='form-errors'>
        {% for error in form.non_field_errors %}
            <li>{{ error }}</li>
        {% endfor %}
    </ul>
{% endif %}

Working with forms¶

About this document

This document provides an introduction to the basics of web forms and how
they are handled in Django. For a more detailed look at specific areas of
the forms API, see The Forms API, Form fields, and
Form and field validation.

Unless you’re planning to build websites and applications that do nothing but
publish content, and don’t accept input from your visitors, you’re going to
need to understand and use forms.

Django provides a range of tools and libraries to help you build forms to
accept input from site visitors, and then process and respond to the input.

HTML forms¶

In HTML, a form is a collection of elements inside <form>...</form> that
allow a visitor to do things like enter text, select options, manipulate
objects or controls, and so on, and then send that information back to the
server.

Some of these form interface elements — text input or checkboxes — are built
into HTML itself. Others are much more complex; an interface that pops up a
date picker or allows you to move a slider or manipulate controls will
typically use JavaScript and CSS as well as HTML form <input> elements to
achieve these effects.

As well as its <input> elements, a form must specify two things:

  • where: the URL to which the data corresponding to the user’s input should
    be returned
  • how: the HTTP method the data should be returned by

As an example, the login form for the Django admin contains several
<input> elements: one of type="text" for the username, one of
type="password" for the password, and one of type="submit" for the
“Log in” button. It also contains some hidden text fields that the user
doesn’t see, which Django uses to determine what to do next.

It also tells the browser that the form data should be sent to the URL
specified in the <form>’s action attribute — /admin/ — and that it
should be sent using the HTTP mechanism specified by the method attribute —
post.

When the <input type="submit" value="Log in"> element is triggered, the
data is returned to /admin/.

GET and POST

GET and POST are the only HTTP methods to use when dealing with forms.

Django’s login form is returned using the POST method, in which the browser
bundles up the form data, encodes it for transmission, sends it to the server,
and then receives back its response.

GET, by contrast, bundles the submitted data into a string, and uses this
to compose a URL. The URL contains the address where the data must be sent, as
well as the data keys and values. You can see this in action if you do a search
in the Django documentation, which will produce a URL of the form
https://docs.djangoproject.com/search/?q=forms&release=1.

GET and POST are typically used for different purposes.

Any request that could be used to change the state of the system — for example,
a request that makes changes in the database — should use POST. GET
should be used only for requests that do not affect the state of the system.

GET would also be unsuitable for a password form, because the password
would appear in the URL, and thus, also in browser history and server logs,
all in plain text. Neither would it be suitable for large quantities of data,
or for binary data, such as an image. A web application that uses GET
requests for admin forms is a security risk: it can be easy for an attacker to
mimic a form’s request to gain access to sensitive parts of the system.
POST, coupled with other protections like Django’s CSRF protection offers more control over access.

On the other hand, GET is suitable for things like a web search form,
because the URLs that represent a GET request can easily be bookmarked,
shared, or resubmitted.

Django’s role in forms¶

Handling forms is a complex business. Consider Django’s admin, where numerous
items of data of several different types may need to be prepared for display in
a form, rendered as HTML, edited using a convenient interface, returned to the
server, validated and cleaned up, and then saved or passed on for further
processing.

Django’s form functionality can simplify and automate vast portions of this
work, and can also do it more securely than most programmers would be able to
do in code they wrote themselves.

Django handles three distinct parts of the work involved in forms:

  • preparing and restructuring data to make it ready for rendering
  • creating HTML forms for the data
  • receiving and processing submitted forms and data from the client

It is possible to write code that does all of this manually, but Django can
take care of it all for you.

Forms in Django¶

We’ve described HTML forms briefly, but an HTML <form> is just one part of
the machinery required.

In the context of a web application, ‘form’ might refer to that HTML
<form>, or to the Django Form that produces it, or to the
structured data returned when it is submitted, or to the end-to-end working
collection of these parts.

The Django Form class¶

At the heart of this system of components is Django’s Form class. In
much the same way that a Django model describes the logical structure of an
object, its behavior, and the way its parts are represented to us, a
Form class describes a form and determines how it works and appears.

In a similar way that a model class’s fields map to database fields, a form
class’s fields map to HTML form <input> elements. (A ModelForm
maps a model class’s fields to HTML form <input> elements via a
Form; this is what the Django admin is based upon.)

A form’s fields are themselves classes; they manage form data and perform
validation when a form is submitted. A DateField and a
FileField handle very different kinds of data and have to do
different things with it.

A form field is represented to a user in the browser as an HTML “widget” — a
piece of user interface machinery. Each field type has an appropriate default
Widget class, but these can be overridden as
required.

Instantiating, processing, and rendering forms¶

When rendering an object in Django, we generally:

  1. get hold of it in the view (fetch it from the database, for example)
  2. pass it to the template context
  3. expand it to HTML markup using template variables

Rendering a form in a template involves nearly the same work as rendering any
other kind of object, but there are some key differences.

In the case of a model instance that contained no data, it would rarely if ever
be useful to do anything with it in a template. On the other hand, it makes
perfect sense to render an unpopulated form — that’s what we do when we want
the user to populate it.

So when we handle a model instance in a view, we typically retrieve it from the
database. When we’re dealing with a form we typically instantiate it in the
view.

When we instantiate a form, we can opt to leave it empty or prepopulate it, for
example with:

  • data from a saved model instance (as in the case of admin forms for editing)
  • data that we have collated from other sources
  • data received from a previous HTML form submission

The last of these cases is the most interesting, because it’s what makes it
possible for users not just to read a website, but to send information back
to it too.

Building a form¶

The work that needs to be done¶

Suppose you want to create a simple form on your website, in order to obtain
the user’s name. You’d need something like this in your template:

<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>

This tells the browser to return the form data to the URL /your-name/, using
the POST method. It will display a text field, labeled “Your name:”, and a
button marked “OK”. If the template context contains a current_name
variable, that will be used to pre-fill the your_name field.

You’ll need a view that renders the template containing the HTML form, and
that can supply the current_name field as appropriate.

When the form is submitted, the POST request which is sent to the server
will contain the form data.

Now you’ll also need a view corresponding to that /your-name/ URL which will
find the appropriate key/value pairs in the request, and then process them.

This is a very simple form. In practice, a form might contain dozens or
hundreds of fields, many of which might need to be prepopulated, and we might
expect the user to work through the edit-submit cycle several times before
concluding the operation.

We might require some validation to occur in the browser, even before the form
is submitted; we might want to use much more complex fields, that allow the
user to do things like pick dates from a calendar and so on.

At this point it’s much easier to get Django to do most of this work for us.

Building a form in Django¶

The Form class¶

We already know what we want our HTML form to look like. Our starting point for
it in Django is this:

forms.py

from django import forms

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

This defines a Form class with a single field (your_name). We’ve
applied a human-friendly label to the field, which will appear in the
<label> when it’s rendered (although in this case, the label
we specified is actually the same one that would be generated automatically if
we had omitted it).

The field’s maximum allowable length is defined by
max_length. This does two things. It puts a
maxlength="100" on the HTML <input> (so the browser should prevent the
user from entering more than that number of characters in the first place). It
also means that when Django receives the form back from the browser, it will
validate the length of the data.

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:

  • return True
  • place the form’s data in its cleaned_data attribute.

The whole form, when rendered for the first time, will look like:

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

Note that it does not include the <form> tags, or a submit button.
We’ll have to provide those ourselves in the template.

The view¶

Form data sent back to a Django website is processed by a view, generally the
same view which published the form. This allows us to reuse some of the same
logic.

To handle the form we need to instantiate it in the view for the URL where we
want it to be published:

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})

If we arrive at this view with a GET request, it will create an empty form
instance and place it in the template context to be rendered. This is what we
can expect to happen the first time we visit the URL.

If the form is submitted using a POST request, the view will once again
create a form instance and populate it with data from the request: form =
NameForm(request.POST)
This is called “binding data to the form” (it is now
a bound form).

We call the form’s is_valid() method; if it’s not True, we go back to
the template with the form. This time the form is no longer empty (unbound)
so the HTML form will be populated with the data previously submitted, where it
can be edited and corrected as required.

If is_valid() is True, we’ll now be able to find all the validated form
data in its cleaned_data attribute. We can use this data to update the
database or do other processing before sending an HTTP redirect to the browser
telling it where to go next.

The template¶

We don’t need to do much in our name.html template:

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

All the form’s fields and their attributes will be unpacked into HTML markup
from that {{ form }} by Django’s template language.

Forms and Cross Site Request Forgery protection

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)
    sender = forms.EmailField()
    cc_myself = 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, sender and
cc_myself. CharField, EmailField and
BooleanField are just three of the available field types; a full list
can be found in Form fields.

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.

Note

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, cc_myself 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 send_mail

if form.is_valid():
    subject = form.cleaned_data['subject']
    message = form.cleaned_data['message']
    sender = form.cleaned_data['sender']
    cc_myself = form.cleaned_data['cc_myself']

    recipients = ['info@example.com']
    if cc_myself:
        recipients.append(sender)

    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect('/thanks/')

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.

Changed in Django 4.0:

Template rendering of forms was added.

Changed in Django 4.1:

The ability to set the default form_template_name on the form renderer
was added.

Form rendering options¶

There are other output options though for the <label>/<input> pairs:

  • {{ form.as_div }} will render them wrapped in <div> tags.
  • {{ form.as_table }} will render them as table cells wrapped in <tr>
    tags.
  • {{ form.as_p }} will render them wrapped in <p> tags.
  • {{ form.as_ul }} will render them wrapped in <li> tags.

Note that you’ll have to provide the surrounding <table> or <ul>
elements yourself.

Here’s the output of {{ form.as_p }} for our ContactForm instance:

<p><label for="id_subject">Subject:</label>
    <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label>
    <textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
    <input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>

Note that each form field has an ID attribute set to id_<field-name>, which
is referenced by the accompanying label tag. This is important in ensuring that
forms are accessible to assistive technology such as screen reader software.
You can also customize the way in which labels and ids are generated.

See Outputting forms as HTML for more on this.

Rendering fields manually¶

We don’t have to let Django unpack the form’s fields; we can do it manually if
we like (allowing us to reorder the fields, for example). Each field is
available as an attribute of the form using {{ form.name_of_field }}, and
in a Django template, will be rendered appropriately. 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.sender.errors }}
    <label for="{{ form.sender.id_for_label }}">Your email address:</label>
    {{ form.sender }}
</div>
<div class="fieldWrapper">
    {{ form.cc_myself.errors }}
    <label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
    {{ form.cc_myself }}
</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>Sender 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">{{ 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_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. Email address.
{{ 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_email">Email address:</label>

{{ field.legend_tag }}

New in Django 4.1.

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 }}

New in Django 4.1.

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.

See also

For a complete list of attributes and methods, see
BoundField.

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

See also

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

Built-in Form Field Validations in Django Forms are the default validations that come predefined to all fields. Every field comes in with some built-in validations from Django validators. Each Field class constructor takes some fixed arguments.

The error_messages argument lets you specify manual error messages for attributes of the field. The error_messages argument lets you override the default messages that the field will raise. Pass in a dictionary with keys matching the error messages you want to override. For example, here is the default error message:

>>> from django import forms
>>> generic = forms.CharField()
>>> generic.clean('')
Traceback (most recent call last):
  ...
ValidationError: ['This field is required.']

And here is a custom error message:

>>> name = forms.CharField(
                error_messages={
               'required': 'Please enter your name'
                })
>>> name.clean('')
Traceback (most recent call last):
  ...
ValidationError: ['Please enter your name']

Syntax

field_name = models.Field(option = value)

Django Form Field Validation error_messages Explanation

Illustration of error_messages using an Example. Consider a project named geeksforgeeks having an app named geeks.

Refer to the following articles to check how to create a project and an app in Django.

  • How to Create a Basic Project using MVT in Django?
  • How to Create an App in Django ?

Enter the following code into forms.py file of geeks app. We will be using CharField for experimenting for all field options.

from django import forms

class GeeksForm(forms.Form):

    geeks_field = forms.CharField(

                  error_messages = {

                 'required':"Please Enter your Name"

                 })

Add the geeks app to INSTALLED_APPS

INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'geeks',

]

Now to render this form into a view we need a view and a URL mapped to that view. Let’s create a view first in views.py of geeks app,

from django.shortcuts import render

from .forms import GeeksForm

def home_view(request):

    context = {}

    form = GeeksForm(request.POST or None)

    context['form'] = form

    if request.POST:

        if form.is_valid():

            temp = form.cleaned_data.get("geeks_field")

            print(temp)

    return render(request, "home.html", context)

Here we are importing that particular form from forms.py and creating an object of it in the view so that it can be rendered in a template.
Now, to initiate a Django form you need to create home.html where one would be designing the stuff as they like. Let’s create a form in home.html.

<form method = "POST">

    {% csrf_token %}

    {{ form }}

    <input type = "submit" value = "Submit">

</form>

Finally, a URL to map to this view in urls.py

from django.urls import path

from .views import home_view

URLpatterns = [

    path('', home_view ),

]

Let’s run the server and check what has actually happened, Run

Python manage.py runserver

error_messages - Django Form Field Validation

Now let’s try to submit it empty and check if required error_message has been overridden.

error_messages-Django-Form-Field-Validation

Thus the field is displaying a custom error message for required attribute of Charfield.

More Built-in Form Validations

Field Options Description
required By default, each Field class assumes the value is required, so to make it not required you need to set required=False
label The label argument lets you specify the “human-friendly” label for this field. This is used when the Field is displayed in a Form.
label_suffix The label_suffix argument lets you override the form’s label_suffix on a per-field basis.
widget The widget argument lets you specify a Widget class to use when rendering this Field. See Widgets for more information.
help_text The help_text argument lets you specify descriptive text for this Field. If you provide help_text, it will be displayed next to the Field when the Field is rendered by one of the convenience Form methods.
error_messages The error_messages argument lets you override the default messages that the field will raise. Pass in a dictionary with keys matching the error messages you want to override.
validators The validators argument lets you provide a list of validation functions for this field.
localize The localize argument enables the localization of form data input, as well as the rendered output.
disabled. The disabled boolean argument, when set to True, disables a form field using the disabled HTML attribute so that it won’t be editable by users.

In this post we’ll learn to create user-defined functions, displaying validation errors in the template for Django Form Validations.

Table Of Contents

  • Introduction
  • Creating Form
  • Rendering Form
  • Saving Form
  • Form Validation User-Defined Functions
  • Conclusion

Introduction

The forms are a Django Module which deals with all form-related functions from binding POST data to form, Validating form and rendering HTML field in the template.
We’ll be using below models.py file as an example to demonstrate form validations.

from django.db import models
from django.contrib.auth.models import User
from datetime import datetime

class AuthUserProfile(models.Model):
    user_profile_id = models.AutoField(primary_key=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='auth_user_profile')
    dob =  models.DateField(blank=True, null=True)
    is_deleted = models.PositiveSmallIntegerField(default=0)
    created_at = models.DateTimeField(auto_now=datetime.now(), null=True)
    updated_at = models.DateTimeField(auto_now=datetime.now(), null=True)

    class Meta():
        db_table = 'auth_user_profile'
        verbose_name = 'User Profile'
        verbose_name_plural = 'User Profiles'

    def __str__(self):
        return self.user

Create a form which has these fields (first_name, last_name, username, password, email) from User models and field (dob) in AuthUserProfile Model and also will add custom field and non-field level validation.

Creating Form

In forms.py file import forms from Django. Inherit forms.Form to UserForm and add attributes to the field.

from django import forms
from datetime import datetime
from django.contrib.auth.models import User

class UserForm(forms.Form):
    first_name = forms.CharField(label="First Name*",widget=forms.TextInput(attrs={'required':True,'class':"form-control"}))
    last_name = forms.CharField(label="Last Name*",widget=forms.TextInput(attrs={'required':True,'class':"form-control"}))
    username = forms.CharField(label="User Name*",widget=forms.TextInput(attrs={'required':True,'class':"form-control"}))
    email = forms.CharField(label="Email",widget=forms.TextInput(attrs={'type':'email','required':False,'class':"form-control"}))
    date_of_birth = forms.CharField(label="Date of Birth",widget=forms.TextInput(attrs={'type':'date','required':True,'class':"form-control"}))
    password = forms.CharField(label="Password*",widget=forms.TextInput(attrs={'required':True,'class':"form-control", 'type' : "password"}))
    confirm_password = forms.CharField(label="Confirm Password*",widget=forms.TextInput(attrs={'required':True,'class':"form-control", 'type' : "password"}))
    
    def clean(self):
        # user age must be above 18 to register
        if self.cleaned_data.get('date_of_birth'):
            dob = datetime.strptime(self.cleaned_data.get('date_of_birth'),"%Y-%m-%d")
            now = datetime.now()
            diff = now.year-dob.year

            if diff < 18: msg="User must be atleast 18 years old" self.add_error(None, msg) #check if user name is unique username_count = User.objects.filter(username=self.cleaned_data.get('username')).count() if username_count>0:
            msg="Username '{}' has already been used.".format(self.cleaned_data.get('username'))
            self.add_error(None, msg)
        
    def clean_confirm_password(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if confirm_password!=password:
            msg = "Password and Confirm Passwords must match."
            self.add_error('confirm_password', msg)

You may notice clean() and clean_confirm_password() methods in UserForm the form they are validation methods.
The clean() the method is form level validation this can also be used to perform field-level validation.

And the clean_confirm_password() is a field-level validation for confirm_password the field it checks if confirm_password!=password then adds error to a then particular field.

Rendering Form

Rendering of forms is an easy part we must pass the form object as an argument to render function.

In views.py create a function user_profile_create which will display rendered form.

from django.contrib.auth.models import User
from users.models import AuthUserProfile
from forms.forms import UserForm
from django.contrib.auth.hashers import make_password
from django.contrib import messages

def user_profile_create(request):
    form = UserForm()
    template="forms/user_profile_create_form.html"
    return render(request,template,{"form":form})

form = UserForm() creates form object of UserForm and is passed as an argument to the render() function.

In urls.py file add routes to view.

urlpatterns = [
    path('user/profile/create', views.user_profile_create, name='user-profile-create'),
]

Create an HTML file in your apps template folder naming user_profile_create_form.html.

<!DOCTYPE html>
<html lang="en">            
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Django Form Validation</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
        <style>
            .error{
                color:red;
            }
        </style>
    </head>            
    <body>
        <div class="container">
        
            {% if messages %}
                {% for message in messages %}
                    {% if message.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %}
                    <div class="alert alert-success"
                    role="alert">
                        <div id="primary-notification-div">
                            {{ message }}
                        </div>
                    </div>
                    {% endif %}
                {% endfor %}
            {% endif %}
                
            <h1>User Profile</h1>
            <form action="{% url 'forms:user-profile-save' %}" method="post">
                {% csrf_token %}
    
                {% if form.errors %}
                    {% for error in form.non_field_errors %}
                        <div class="alert alert-danger">
                            <strong>{{ error|escape }}</strong>
                        </div>
                    {% endfor %}
    
                {% endif %}
    
    
                <div class="row">
                    <div class="col-md-3">
                        {{form.first_name.label}}
                        {{form.first_name}}
    
                        {% if form.errors.first_name %}
                            <label for="" class="error">{{form.errors.first_name|striptags}}</label>
                        {% endif %}
                    </div>
    
                    <div class="col-md-3">
                        {{form.last_name.label}}
                        {{form.last_name}}
                        {% if form.errors.last_name %}
                            <label for="" class="error">{{form.errors.last_name|striptags}}</label>
                        {% endif %}
                    </div>
    
                    <div class="col-md-3">
                        {{form.username.label}}
                        {{form.username}}
                        {% if form.errors.username %}
                            <label for="" class="error">{{form.errors.username|striptags}}</label>
                        {% endif %}
                    </div>
    
                    <div class="col-md-3">
                        {{form.email.label}}
                        {{form.email}}
                        {% if form.errors.email %}
                            <label for="" class="error">{{form.errors.email|striptags}}</label>
                        {% endif %}
                    </div>
    
                    <div class="col-md-3">
                        {{form.date_of_birth.label}}
                        {{form.date_of_birth}}
                        {% if form.errors.date_of_birth %}
                            <label for="" class="error">{{form.errors.date_of_birth|striptags}}</label>
                        {% endif %}
                    </div>
                </div>
    
                <div class="row" style="margin-top: 25px;">
                    <div class="col-md-3">
                        {{form.password.label}}
                        {{form.password}}
                        {% if form.errors.password %}
                            <label for="" class="error">{{form.errors.password|striptags}}</label>
                        {% endif %}
                    </div>
                </div>
    
                <div class="row" style="margin-top: 25px;">
    
                    <div class="col-md-3">
                        {{form.confirm_password.label}}
                        {{form.confirm_password}}
                        {% if form.errors.confirm_password %}
                        <label for="" class="error">{{form.errors.confirm_password|striptags}}</label>
                        {% endif %}
                    </div>
    
                    <div class="col-md-12" style="margin-top: 25px;">
                        <input type="submit" class="btn btn-sm btn-primary" value="submit">
                    </div>
                </div>
            </form>
        </div>
    </body>                
</html>

This is how our form will look when we go to route user/profile/create.

User Profile Form

  • The message displays success message once messages.add_message(request, messages.SUCCESS, ".....") is called it is just like the flash message.
  • The form.errors is called on validation has failed.
  • The form.non_field_errors display errors on top of form this errors are not associated to a particular field.
  • The form.errors. displays the error of the particular field.

This is how errors are displayed in the form.

User Profile Form Displaying Validation Errors

Saving Form

In urls.py file add routes to save the form.

urlpatterns = [
    path('user/profile/save', views.user_profile_create, name='user-profile-save'),
]

In views.py file add function user_profile_save() to save form data.

def user_profile_save(request):

    form = UserForm(request.POST)

    if form.is_valid():

        query = {
            "first_name" : form.cleaned_data.get('first_name'),
            "last_name" : form.cleaned_data.get('last_name'),
            "username" : form.cleaned_data.get('username'),
            "password" : make_password(form.cleaned_data.get('password')),
            "email" : form.cleaned_data.get('email'),
            "is_superuser" : 0,
            "is_staff" : 1,
            "is_active" : 1,
        }

        user = User.objects.create(**query)
        
        query={
            "user_id" : user.id,
            "dob" : form.cleaned_data.get('dob'),
        }
        
        AuthUserProfile.objects.create(**query)
        
        messages.add_message(request, messages.SUCCESS, "User Profile created successfully.")
        
        return HttpResponseRedirect(reverse('forms:user-profile-create'))
    
    template="forms/user_profile_create_form.html"
    
    return render(request,template,{"form":form})

The request.POST is passed to UserForm(request.POST) this binds the submitted data to Form Class.
The form.is_valid() returns a Boolean value if True then the form is clean and if False then there may be validation error.
To view validation errors after .is_valid() method we can print form.errors to view validation errors.

Calling form.cleaned_data.get('') gives use of the sanitized value to that field. Inside .is_valid() we have called model methods to save form data.

Showing success message on successfully validating form and saving its contents into the database

Form Validation User-Defined functions

To defined a custom validation function in Form Class name function with prefix clean followed by underscore and field name which must be validated.

Example

def clean_first_name(self):
    pass #this validates field first_name

def clean_username(self):
    pass #this validates field username

If the value of the field is not as expected that you can raise validation error or add error by mentioning field name self.add_error('field_name', "Error Message").
If you want to raise non-field error than set the first argument of add_error() method None followed by the message you want to be displayed.

self.add_error(None, msg) #this creates a non-field error

Conclusion

We have come to the end of our post on Django Form Validation.
If you have any doubts or suggestions please mention in the comments section and we’ll reach you soon and we would also love to hear requests and your recommendations for new tutorials/posts.

Related Posts

  • Python Django Forms | Creating, Rendering, Validating and Saving Forms
  • Django – Multiple Files Validation and Uploads

Summary

Review Date

2020-06-15

Reviewed Item

Django Forms | Custom Form Validations

Author Rating

51star1star1star1star1star

Software Name

Django Web Framework

Software Name

Windows Os, Mac Os, Ubuntu Os

Software Category

Web Development

Этот документ объясняет использование системы аутентификации Django в конфигурации по умолчанию. Эта конфигурация развивалась для удовлетворения наиболее распространенных потребностей проекта, обрабатывая достаточно широкий спектр задач, и имеет тщательную реализацию паролей и разрешений. Для проектов, где потребности в аутентификации отличаются от конфигурации по умолчанию, Django поддерживает расширенные extension and customization> аутентификации.

Django authentication обеспечивает аутентификацию и авторизацию вместе и обычно называется системой аутентификации, поскольку эти функции в некоторой степени связаны между собой.

User объекты¶

Объекты User являются ядром системы аутентификации. Они обычно представляют людей, взаимодействующих с вашим сайтом, и используются для таких вещей, как ограничение доступа, регистрация профилей пользователей, ассоциирование контента с создателями и т.д. В системе аутентификации Django существует только один класс пользователей, т.е. пользователи 'superusers' или admin 'staff' — это просто объекты пользователей с установленными специальными атрибутами, а не разные классы объектов пользователей.

Основными атрибутами пользователя по умолчанию являются:

  • username
  • password
  • email
  • first_name
  • last_name

См. full API documentation для полной справки, следующая документация больше ориентирована на задачи.

Создание пользователей¶

Самый прямой способ создания пользователей — использовать включенную вспомогательную функцию create_user():

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')

# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()

Если у вас установлен админ Django, вы также можете create users interactively.

Создание суперпользователей¶

Создайте суперпользователей с помощью команды createsuperuser:

$ python manage.py createsuperuser --username=joe --email=joe@example.com

Вам будет предложено ввести пароль. После ввода пароля пользователь будет создан немедленно. Если вы не указали параметры --username или --email, будет предложено ввести эти значения.

Изменение паролей¶

Django не хранит необработанные (открытый текст) пароли в модели пользователя, а только хэш (см. documentation of how passwords are managed для полной информации). В связи с этим не пытайтесь манипулировать атрибутом password пользователя напрямую. Поэтому при создании пользователя используется вспомогательная функция.

Чтобы изменить пароль пользователя, у вас есть несколько вариантов:

manage.py changepassword *username* предлагает метод изменения пароля пользователя из командной строки. Он предлагает вам изменить пароль данного пользователя, который вы должны ввести дважды. Если они оба совпадают, то новый пароль будет немедленно изменен. Если вы не укажете пользователя, команда попытается изменить пароль пользователя, чье имя пользователя совпадает с именем текущего пользователя системы.

Вы также можете изменить пароль программно, используя set_password():

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()

Если у вас установлен админ Django, вы также можете изменить пароли пользователей на странице authentication system’s admin pages.

Django также предоставляет views и forms, которые могут быть использованы для того, чтобы позволить пользователям изменять свои собственные пароли.

Изменение пароля пользователя приведет к выходу из всех его сессий. Подробнее см. в разделе Аннулирование сессии при смене пароля.

Аутентификация пользователей¶

authenticate(request=None, **credentials)[исходный код]

Используйте authenticate() для проверки набора учетных данных. Она принимает учетные данные в качестве аргументов ключевых слов, username и password для случая по умолчанию, сверяет их с каждым authentication backend и возвращает объект User, если учетные данные действительны для бэкенда. Если учетные данные не действительны ни для одного бэкенда или если бэкенд поднимает PermissionDenied, возвращается None. Например:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    # A backend authenticated the credentials
else:
    # No backend authenticated the credentials

request — необязательный HttpRequest, который передается в методе authenticate() бэкендов аутентификации.

Примечание

Это низкоуровневый способ аутентификации набора учетных данных; например, его использует RemoteUserMiddleware. Если вы не пишете свою собственную систему аутентификации, вы, вероятно, не будете ее использовать. Скорее, если вы ищете способ входа пользователя в систему, используйте LoginView.

Разрешения и авторизация¶

Django поставляется со встроенной системой разрешений. Она предоставляет возможность назначать разрешения определенным пользователям и группам пользователей.

Он используется администратором сайта Django, но вы можете использовать его в своем собственном коде.

Административный сайт Django использует разрешения следующим образом:

  • Доступ к объектам просмотра ограничен пользователями, имеющими разрешение «просмотр» или «изменение» для данного типа объекта.
  • Доступ к просмотру формы «Добавить» и добавлению объекта ограничен пользователями с правом «Добавить» для данного типа объекта.
  • Доступ к просмотру списка изменений, форме «изменения» и изменению объекта ограничен пользователями с правом «изменения» для данного типа объекта.
  • Доступ к удалению объекта ограничен пользователями, имеющими разрешение «удалить» для данного типа объекта.

Разрешения могут быть установлены не только для типа объекта, но и для конкретного экземпляра объекта. Используя методы has_view_permission(), has_add_permission(), has_change_permission() и has_delete_permission(), предоставляемые классом ModelAdmin, можно настроить разрешения для различных экземпляров объектов одного типа.

Объекты User имеют два поля типа «многие-ко-многим»: groups и user_permissions. Объекты User могут обращаться к связанным с ними объектам так же, как и к любым другим Django model:

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

Разрешения по умолчанию¶

Когда django.contrib.auth указано в настройках INSTALLED_APPS, это гарантирует, что четыре разрешения по умолчанию — добавление, изменение, удаление и просмотр — будут созданы для каждой модели Django, определенной в одном из ваших установленных приложений.

Эти разрешения будут созданы при запуске manage.py migrate; при первом запуске migrate после добавления django.contrib.auth к INSTALLED_APPS разрешения по умолчанию будут созданы для всех ранее установленных моделей, а также для любых новых моделей, устанавливаемых в это время. После этого он будет создавать разрешения по умолчанию для новых моделей каждый раз, когда вы запускаете manage.py migrate (функция, создающая разрешения, связана с сигналом post_migrate).

Предположим, что у вас есть приложение с app_label foo и моделью с именем Bar, для проверки основных разрешений вы должны использовать:

  • добавить: user.has_perm('foo.add_bar')
  • изменение: user.has_perm('foo.change_bar')
  • удалить: user.has_perm('foo.delete_bar')
  • вид: user.has_perm('foo.view_bar')

К модели Permission редко обращаются напрямую.

Групи¶

django.contrib.auth.models.Group Модели — это общий способ категоризации пользователей, чтобы вы могли применять к ним разрешения или другие метки. Пользователь может принадлежать к любому количеству групп.

Пользователь в группе автоматически имеет разрешения, предоставленные этой группе. Например, если группа Site editors имеет разрешение can_edit_home_page, то любой пользователь в этой группе будет иметь это разрешение.

Помимо прав доступа, группы — это удобный способ разделить пользователей на категории, чтобы дать им определенный ярлык или расширенную функциональность. Например, вы можете создать группу 'Special users', и написать код, который может, скажем, дать им доступ к части вашего сайта, предназначенной только для членов клуба, или отправлять им сообщения по электронной почте, предназначенные только для членов клуба.

Программное создание разрешений¶

Хотя custom permissions может быть определено в классе Meta модели, вы также можете создавать разрешения напрямую. Например, вы можете создать разрешение can_publish для модели BlogPost в myapp:

from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
    codename='can_publish',
    name='Can Publish Posts',
    content_type=content_type,
)

Затем разрешение может быть назначено на User через атрибут user_permissions или на Group через атрибут permissions.

Прокси-модели нуждаются в собственном типе содержимого

Если вы хотите создать permissions for a proxy model, передайте for_concrete_model=False в ContentTypeManager.get_for_model(), чтобы получить соответствующее ContentType:

content_type = ContentType.objects.get_for_model(BlogPostProxy, for_concrete_model=False)

Кэширование разрешений¶

ModelBackend кэширует разрешения на объект пользователя после первого раза, когда они должны быть получены для проверки разрешений. Обычно это подходит для цикла запрос-ответ, поскольку разрешения обычно не проверяются сразу после их добавления (например, в админке). Если вы добавляете разрешения и проверяете их сразу после этого, например, в тесте или представлении, самым простым решением будет повторная выборка пользователя из базы данных. Например:

from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404

from myapp.models import BlogPost

def user_gains_perms(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    # any permission check will cache the current set of permissions
    user.has_perm('myapp.change_blogpost')

    content_type = ContentType.objects.get_for_model(BlogPost)
    permission = Permission.objects.get(
        codename='change_blogpost',
        content_type=content_type,
    )
    user.user_permissions.add(permission)

    # Checking the cached permission set
    user.has_perm('myapp.change_blogpost')  # False

    # Request new instance of User
    # Be aware that user.refresh_from_db() won't clear the cache.
    user = get_object_or_404(User, pk=user_id)

    # Permission cache is repopulated from the database
    user.has_perm('myapp.change_blogpost')  # True

    ...

Модели прокси¶

Прокси-модели работают точно так же, как и конкретные модели. Разрешения создаются с использованием собственного типа содержимого прокси-модели. Прокси-модели не наследуют разрешения конкретной модели, которую они подклассифицируют:

class Person(models.Model):
    class Meta:
        permissions = [('can_eat_pizzas', 'Can eat pizzas')]

class Student(Person):
    class Meta:
        proxy = True
        permissions = [('can_deliver_pizzas', 'Can deliver pizzas')]

>>> # Fetch the content type for the proxy model.
>>> content_type = ContentType.objects.get_for_model(Student, for_concrete_model=False)
>>> student_permissions = Permission.objects.filter(content_type=content_type)
>>> [p.codename for p in student_permissions]
['add_student', 'change_student', 'delete_student', 'view_student',
'can_deliver_pizzas']
>>> for permission in student_permissions:
...     user.user_permissions.add(permission)
>>> user.has_perm('app.add_person')
False
>>> user.has_perm('app.can_eat_pizzas')
False
>>> user.has_perms(('app.add_student', 'app.can_deliver_pizzas'))
True

Аутентификация в веб-запросах¶

Django использует sessions и промежуточное ПО для подключения системы аутентификации к request objects.

Они обеспечивают атрибут request.user в каждом запросе, который представляет текущего пользователя. Если текущий пользователь не вошел в систему, этот атрибут будет установлен в экземпляр AnonymousUser, в противном случае это будет экземпляр User.

Вы можете различать их с помощью is_authenticated, например, так:

if request.user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...

Как войти в систему пользователя¶

Если у вас есть аутентифицированный пользователь, которого вы хотите присоединить к текущей сессии — это делается с помощью функции login().

login(request, user, backend=None)[исходный код]

Чтобы зарегистрировать пользователя в системе из представления, используйте login(). Он принимает объект HttpRequest и объект User. login() сохраняет идентификатор пользователя в сессии, используя фреймворк сессий Django.

Обратите внимание, что любые данные, установленные во время анонимной сессии, сохраняются в сессии после входа пользователя в систему.

Этот пример показывает, как можно использовать authenticate() и login():

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error message.
        ...

Выбор бэкенда аутентификации¶

Когда пользователь входит в систему, его ID и бэкенд, который использовался для аутентификации, сохраняются в сессии пользователя. Это позволяет тому же authentication backend получить данные пользователя при последующем запросе. Бэкэнд аутентификации для сохранения в сессии выбирается следующим образом:

  1. Используйте значение необязательного аргумента backend, если он предоставлен.
  2. Используйте значение атрибута user.backend, если он присутствует. Это позволяет использовать пары authenticate() и login(): authenticate() устанавливает атрибут user.backend на возвращаемом объекте пользователя.
  3. Используйте backend в AUTHENTICATION_BACKENDS, если есть только один.
  4. В противном случае вызовите исключение.

В случаях 1 и 2 значением аргумента backend или атрибута user.backend должна быть строка пути импорта с точкой (как в AUTHENTICATION_BACKENDS), а не реальный класс бэкенда.

Как выйти из системы¶

logout(request)[исходный код]

Чтобы выйти из пользователя, который вошел в систему через django.contrib.auth.login(), используйте django.contrib.auth.logout() в вашем представлении. Она принимает объект HttpRequest и не имеет возвращаемого значения. Пример:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

Обратите внимание, что logout() не выдает никаких ошибок, если пользователь не вошел в систему.

Когда вы вызываете logout(), данные сессии для текущего запроса полностью очищаются. Все существующие данные удаляются. Это делается для того, чтобы другой человек не смог использовать тот же веб-браузер для входа в систему и получить доступ к данным сессии предыдущего пользователя. Если вы хотите поместить в сессию что-либо, что будет доступно пользователю сразу после выхода из нее, сделайте это после вызова django.contrib.auth.logout().

Ограничение доступа для вошедших в систему пользователей¶

Сырой способ¶

Необработанный способ ограничения доступа к страницам заключается в проверке request.user.is_authenticated и либо перенаправлении на страницу входа:

from django.conf import settings
from django.shortcuts import redirect

def my_view(request):
    if not request.user.is_authenticated:
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
    # ...

…или вывести сообщение об ошибке:

from django.shortcuts import render

def my_view(request):
    if not request.user.is_authenticated:
        return render(request, 'myapp/login_error.html')
    # ...

Декоратор login_required

login_required(redirect_field_name=‘next’, login_url=None)[исходный код]

В качестве сокращения можно использовать удобный декоратор login_required():

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

login_required() делает следующее:

  • Если пользователь не вошел в систему, перенаправьте его на settings.LOGIN_URL, передав текущий абсолютный путь в строке запроса. Пример: /accounts/login/?next=/polls/3/.
  • Если пользователь вошел в систему, выполните представление нормально. Код представления может считать, что пользователь вошел в систему.

По умолчанию путь, на который пользователь должен быть перенаправлен после успешной аутентификации, хранится в параметре строки запроса под названием "next". Если вы предпочитаете использовать другое имя для этого параметра, login_required() принимает необязательный параметр redirect_field_name:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
    ...

Обратите внимание, что если вы зададите значение redirect_field_name, то, скорее всего, вам также придется настроить шаблон входа в систему, так как контекстная переменная шаблона, хранящая путь перенаправления, будет использовать в качестве ключа значение redirect_field_name, а не "next" (по умолчанию).

login_required() также принимает необязательный параметр login_url. Пример:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
    ...

Обратите внимание, что если вы не указываете параметр login_url, вам нужно убедиться, что параметр settings.LOGIN_URL и ваше представление входа правильно связаны. Например, используя значения по умолчанию, добавьте следующие строки в URLconf:

from django.contrib.auth import views as auth_views

path('accounts/login/', auth_views.LoginView.as_view()),

settings.LOGIN_URL также принимает имена функций представления и named URL patterns. Это позволяет вам свободно переназначать представление входа в URLconf без необходимости обновлять настройки.

Примечание

Декоратор login_required НЕ проверяет флаг is_active у пользователя, но по умолчанию AUTHENTICATION_BACKENDS отвергает неактивных пользователей.

The LoginRequiredMixin mixin¶

При использовании class-based views можно добиться того же поведения, что и при login_required, используя LoginRequiredMixin. Этот миксин должен находиться на самой левой позиции в списке наследования.

class LoginRequiredMixin

Если представление использует этот миксин, все запросы неаутентифицированных пользователей будут перенаправляться на страницу входа или отображаться ошибка HTTP 403 Forbidden, в зависимости от параметра raise_exception.

Вы можете установить любой из параметров AccessMixin для настройки обработки неавторизованных пользователей:

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

Примечание

Как и декоратор login_required, этот миксин НЕ проверяет флаг is_active на пользователе, но по умолчанию AUTHENTICATION_BACKENDS отклоняет неактивных пользователей.

Ограничение доступа для вошедших в систему пользователей, которые прошли тест¶

Чтобы ограничить доступ на основе определенных разрешений или какого-либо другого теста, вы сделаете практически то же самое, что описано в предыдущем разделе.

Вы можете запустить свой тест на request.user непосредственно в представлении. Например, это представление проверяет, есть ли у пользователя email в нужном домене, и если нет, перенаправляет на страницу входа:

from django.shortcuts import redirect

def my_view(request):
    if not request.user.email.endswith('@example.com'):
        return redirect('/login/?next=%s' % request.path)
    # ...
user_passes_test(test_func, login_url=None, redirect_field_name=‘next’)[исходный код]

В качестве сокращения можно использовать удобный декоратор user_passes_test, который выполняет перенаправление, когда вызываемый объект возвращает False:

from django.contrib.auth.decorators import user_passes_test

def email_check(user):
    return user.email.endswith('@example.com')

@user_passes_test(email_check)
def my_view(request):
    ...

user_passes_test() принимает обязательный аргумент: вызываемый объект, который принимает объект User и возвращает True, если пользователю разрешено просматривать страницу. Обратите внимание, что user_passes_test() не проверяет автоматически, что User не является анонимным.

user_passes_test() принимает два необязательных аргумента:

login_url
Позволяет указать URL, на который будут перенаправлены пользователи, не прошедшие тест. Это может быть страница входа в систему и по умолчанию имеет значение settings.LOGIN_URL, если вы его не укажете.
redirect_field_name
То же самое, что и для login_required(). Установка значения None удаляет его из URL, что может понадобиться, если вы перенаправляете пользователей, не прошедших тест, на страницу без входа в систему, где нет «следующей страницы».

Например:

@user_passes_test(email_check, login_url='/login/')
def my_view(request):
    ...
class UserPassesTestMixin

При использовании class-based views, вы можете использовать UserPassesTestMixin для этого.

test_func()¶

Вы должны переопределить метод test_func() класса, чтобы указать выполняемый тест. Кроме того, вы можете установить любой из параметров AccessMixin для настройки обработки неавторизованных пользователей:

from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')
get_test_func()¶

Вы также можете переопределить метод get_test_func(), чтобы миксин использовал для своих проверок функцию с другим именем (вместо test_func()).

Укладка UserPassesTestMixin

Из-за того, как реализовано UserPassesTestMixin, вы не можете складывать их в список наследования. Следующее НЕ работает:

class TestMixin1(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.email.endswith('@example.com')

class TestMixin2(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.username.startswith('django')

class MyView(TestMixin1, TestMixin2, View):
    ...

Если бы TestMixin1 вызывал super() и учитывал этот результат, TestMixin1 уже не работал бы автономно.

Декоратор permission_required

permission_required(perm, login_url=None, raise_exception=False)[исходный код]

Это довольно распространенная задача — проверить, есть ли у пользователя определенное разрешение. По этой причине Django предоставляет ярлык для этого случая: декоратор permission_required().:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.add_choice')
def my_view(request):
    ...

Как и в методе has_perm(), имена разрешений принимают форму "<app label>.<permission codename>" (например, polls.add_choice для разрешения на модель в приложении polls).

Декоратор также может принимать итерацию разрешений, в этом случае пользователь должен иметь все разрешения, чтобы получить доступ к представлению.

Обратите внимание, что permission_required() также принимает необязательный параметр login_url:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.add_choice', login_url='/loginpage/')
def my_view(request):
    ...

Как и в декораторе login_required(), login_url по умолчанию равен settings.LOGIN_URL.

Если задан параметр raise_exception, декоратор поднимет PermissionDenied, предлагая the 403 (HTTP Forbidden) view вместо перенаправления на страницу входа.

Если вы хотите использовать raise_exception, но при этом дать пользователям возможность сначала войти в систему, вы можете добавить декоратор login_required():

from django.contrib.auth.decorators import login_required, permission_required

@login_required
@permission_required('polls.add_choice', raise_exception=True)
def my_view(request):
    ...

Это также позволяет избежать цикла перенаправления, когда LoginView становится redirect_authenticated_user=True, а у вошедшего пользователя нет всех необходимых прав.

Миксин PermissionRequiredMixin

Чтобы применить проверку разрешений к class-based views, вы можете использовать PermissionRequiredMixin:

class PermissionRequiredMixin

Этот миксин, как и декоратор permission_required, проверяет, имеет ли пользователь, обращающийся к представлению, все заданные разрешения. Вы должны указать разрешение (или итерацию разрешений) с помощью параметра permission_required:

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'polls.add_choice'
    # Or multiple of permissions:
    permission_required = ('polls.view_choice', 'polls.change_choice')

Вы можете установить любой из параметров AccessMixin, чтобы настроить обработку неавторизованных пользователей.

Вы также можете переопределить эти методы:

get_permission_required()¶

Возвращает итерабель имен разрешений, используемых данным микшином. По умолчанию используется атрибут permission_required, при необходимости преобразуется в кортеж.

has_permission()¶

Возвращает булево значение, обозначающее, имеет ли текущий пользователь разрешение на выполнение декорированного представления. По умолчанию возвращается результат вызова has_perms() со списком разрешений, возвращаемым get_permission_required().

Перенаправление несанкционированных запросов в представлениях на основе классов¶

Чтобы облегчить обработку ограничений доступа в class-based views, AccessMixin можно использовать для настройки поведения представления при отказе в доступе. Аутентифицированным пользователям отказывается в доступе с ответом HTTP 403 Forbidden. Анонимные пользователи перенаправляются на страницу входа или показывают ответ HTTP 403 Forbidden, в зависимости от атрибута raise_exception.

class AccessMixin
login_url

Возвращаемое значение по умолчанию для get_login_url(). По умолчанию None, в этом случае get_login_url() возвращается к settings.LOGIN_URL.

permission_denied_message

Возвращаемое значение по умолчанию для get_permission_denied_message(). По умолчанию это пустая строка.

redirect_field_name

Возвращаемое значение по умолчанию для get_redirect_field_name(). По умолчанию возвращается значение "next".

raise_exception

Если этот атрибут установлен в True, то при невыполнении условий возникает исключение PermissionDenied. Если False (по умолчанию), анонимные пользователи перенаправляются на страницу входа в систему.

get_login_url()¶

Возвращает URL, на который будут перенаправлены пользователи, не прошедшие тест. Возвращает login_url, если установлено, или settings.LOGIN_URL в противном случае.

get_permission_denied_message()¶

Когда raise_exception равно True, этот метод можно использовать для управления сообщением об ошибке, передаваемым в обработчик ошибок для отображения пользователю. По умолчанию возвращает атрибут permission_denied_message.

get_redirect_field_name()¶

Возвращает имя параметра запроса, который будет содержать URL, на который пользователь должен быть перенаправлен после успешного входа в систему. Если вы установите значение None, параметр запроса не будет добавлен. По умолчанию возвращает атрибут redirect_field_name.

handle_no_permission()¶

В зависимости от значения raise_exception, метод либо вызывает исключение PermissionDenied, либо перенаправляет пользователя на login_url, по желанию включая redirect_field_name, если оно установлено.

Аннулирование сессии при смене пароля¶

Если ваш AUTH_USER_MODEL наследует от AbstractBaseUser или реализует свой собственный метод get_session_auth_hash(), аутентифицированные сессии будут включать хэш, возвращаемый этой функцией. В случае AbstractBaseUser это HMAC поля пароля. Django проверяет, что хэш в сессии для каждого запроса совпадает с тем, который вычисляется во время запроса. Это позволяет пользователю выйти из всех своих сессий, изменив пароль.

Представления смены пароля по умолчанию, входящие в Django, PasswordChangeView и представление user_change_password в админке django.contrib.auth, обновляют сессию новым хэшем пароля, чтобы пользователь, меняющий свой пароль, не вышел из системы. Если у вас есть пользовательское представление смены пароля и вы хотите иметь подобное поведение, используйте функцию update_session_auth_hash().

update_session_auth_hash(request, user)[исходный код]

Эта функция принимает текущий запрос и обновленный объект пользователя, из которого будет получен новый хэш сессии, и соответствующим образом обновляет хэш сессии. Она также поворачивает ключ сессии, чтобы украденная сессионная cookie была недействительна.

Пример использования:

from django.contrib.auth import update_session_auth_hash

def password_change(request):
    if request.method == 'POST':
        form = PasswordChangeForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, form.user)
    else:
        ...

Представления аутентификации¶

Django предоставляет несколько представлений, которые вы можете использовать для обработки входа, выхода и управления паролями. В них используется stock auth forms, но вы можете передавать и свои собственные формы.

Django не предоставляет шаблонов по умолчанию для представлений аутентификации. Вы должны создать свои собственные шаблоны для представлений, которые вы хотите использовать. Контекст шаблона документирован в каждом представлении, см. Все виды аутентификации.

Использование представлений¶

Существуют различные методы реализации этих представлений в вашем проекте. Самый простой способ — включить предоставленный URLconf в django.contrib.auth.urls в ваш собственный URLconf, например:

urlpatterns = [
    path('accounts/', include('django.contrib.auth.urls')),
]

Это будет включать следующие шаблоны URL:

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']

Представления предоставляют имя URL для более удобного использования. Подробнее об использовании именованных шаблонов URL см. в the URL documentation.

Если вы хотите получить больший контроль над своими URL-адресами, вы можете сослаться на определенное представление в URLconf:

from django.contrib.auth import views as auth_views

urlpatterns = [
    path('change-password/', auth_views.PasswordChangeView.as_view()),
]

Представления имеют необязательные аргументы, которые можно использовать для изменения поведения представления. Например, если вы хотите изменить имя шаблона, которое использует представление, вы можете указать аргумент template_name. Для этого в URLconf можно указать аргументы в виде ключевых слов, которые будут переданы представлению. Например:

urlpatterns = [
    path(
        'change-password/',
        auth_views.PasswordChangeView.as_view(template_name='change-password.html'),
    ),
]

Все представления являются class-based, что позволяет легко настраивать их с помощью подклассов.

Все виды аутентификации¶

Это список со всеми представлениями, которые предоставляет django.contrib.auth. Подробности реализации смотрите в Использование представлений.

class LoginView

Имя URL: login

Подробнее об использовании именованных шаблонов URL см. в разделе the URL documentation.

Методы и атрибуты

template_name

Имя шаблона, отображаемого для представления, используемого для входа пользователя в систему. По умолчанию имеет значение registration/login.html.

next_page

New in Django 4.0.

URL для перенаправления после входа в систему. По умолчанию LOGIN_REDIRECT_URL.

redirect_field_name

Имя поля GET, содержащего URL для перенаправления после входа в систему. По умолчанию используется next. Переопределяет URL get_default_redirect_url(), если передан заданный параметр GET.

authentication_form

Вызываемый объект (обычно класс формы), который будет использоваться для аутентификации. По умолчанию AuthenticationForm.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

redirect_authenticated_user

Булево значение, определяющее, будут ли аутентифицированные пользователи, зашедшие на страницу входа, перенаправлены так, как будто они только что успешно вошли в систему. По умолчанию имеет значение False.

Предупреждение

Если вы включите опцию redirect_authenticated_user, другие сайты смогут определить, авторизованы ли их посетители на вашем сайте, запрашивая URL перенаправления на файлы изображений на вашем сайте. Чтобы избежать такой утечки информации social media fingerprinting», размещайте все изображения и ваш favicon на отдельном домене.

Включение redirect_authenticated_user также может привести к циклу перенаправления при использовании декоратора permission_required(), если не используется параметр raise_exception.

success_url_allowed_hosts

set хостов, в дополнение к request.get_host(), которые безопасны для перенаправления после входа в систему. По умолчанию используется пустой set.

get_default_redirect_url()¶

New in Django 4.0.

Возвращает URL для перенаправления после входа в систему. Реализация по умолчанию разрешает и возвращает next_page, если установлен, или LOGIN_REDIRECT_URL в противном случае.

Вот что делает LoginView:

  • При вызове через GET отображается форма входа в систему, которая POSTs на тот же URL. Подробнее об этом чуть позже.
  • При вызове через POST с учетными данными, предоставленными пользователем, он пытается войти в систему. В случае успешного входа представление перенаправляется на URL, указанный в next. Если next не указан, он перенаправляется на settings.LOGIN_REDIRECT_URL (по умолчанию на /accounts/profile/). Если вход не был успешным, отображается форма входа.

Вы обязаны предоставить html для шаблона входа в систему, который по умолчанию называется registration/login.html. Этому шаблону передаются четыре контекстные переменные шаблона:

  • form: Объект Form, представляющий AuthenticationForm.
  • next: URL для перенаправления после успешного входа в систему. Он также может содержать строку запроса.
  • site: Текущий Site, в соответствии с настройкой SITE_ID. Если у вас не установлен фреймворк сайта, это будет установлено в экземпляр RequestSite, который берет имя сайта и домен из текущего HttpRequest.
  • site_name: Псевдоним для site.name. Если у вас не установлен фреймворк сайта, это значение будет установлено в значение request.META['SERVER_NAME']. Подробнее о сайтах смотрите Структура «сайтов».

Если вы предпочитаете не вызывать шаблон registration/login.html, вы можете передать параметр template_name через дополнительные аргументы методу as_view в вашем URLconf. Например, эта строка URLconf будет использовать myapp/login.html вместо:

path('accounts/login/', auth_views.LoginView.as_view(template_name='myapp/login.html')),

Вы также можете указать имя поля GET, которое содержит URL-адрес для перенаправления на него после входа в систему с помощью redirect_field_name. По умолчанию поле называется next.

Вот пример шаблона registration/login.html, который вы можете использовать в качестве отправной точки. Он предполагает, что у вас есть шаблон base.html, определяющий блок content:

{% extends "base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
    {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
    {% else %}
    <p>Please login to see this page.</p>
    {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>

{# Assumes you set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

Если вы настроили аутентификацию (см. Customizing Authentication), вы можете использовать пользовательскую форму аутентификации, установив атрибут authentication_form. Эта форма должна принимать аргумент с ключевым словом request в своем методе __init__() и предоставлять метод get_user(), который возвращает объект аутентифицированного пользователя (этот метод вызывается только после успешной проверки формы).

class LogoutView

Выводит пользователя из системы при запросе POST.

Не рекомендуется, начиная с версии 4.1: Поддержка выхода из системы при запросах GET устарела и будет удалена в Django 5.0.

Имя URL: logout

Атрибуты:

next_page

URL для перенаправления после выхода из системы. По умолчанию LOGOUT_REDIRECT_URL.

template_name

Полное имя шаблона для отображения после выхода пользователя из системы. По умолчанию имеет значение registration/logged_out.html.

redirect_field_name

Имя поля GET, содержащего URL для перенаправления после выхода из системы. По умолчанию используется значение 'next'. Переопределяет URL next_page, если передан заданный параметр GET.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

success_url_allowed_hosts

set хостов, в дополнение к request.get_host(), которые безопасны для перенаправления после выхода из системы. По умолчанию используется пустое значение set.

Контекст шаблона:

  • title: Строка «Logged out», локализована.
  • site: Текущий Site, в соответствии с настройкой SITE_ID. Если у вас не установлен фреймворк сайта, это будет установлено в экземпляр RequestSite, который берет имя сайта и домен из текущего HttpRequest.
  • site_name: Псевдоним для site.name. Если у вас не установлен фреймворк сайта, это значение будет установлено в значение request.META['SERVER_NAME']. Подробнее о сайтах смотрите Структура «сайтов».
logout_then_login(request, login_url=None

Выводит пользователя из системы при запросе POST, затем перенаправляет на страницу входа в систему.

Имя URL: URL по умолчанию не предоставляется

Дополнительные аргументы:

  • login_url: URL страницы входа в систему для перенаправления. По умолчанию settings.LOGIN_URL, если не указан.

Не рекомендуется, начиная с версии 4.1: Поддержка выхода из системы при запросах GET устарела и будет удалена в Django 5.0.

class PasswordChangeView

Имя URL: password_change

Позволяет пользователю изменить свой пароль.

Атрибуты:

template_name

Полное имя шаблона, который будет использоваться для отображения формы смены пароля. По умолчанию registration/password_change_form.html, если не указано.

success_url

URL для перенаправления после успешной смены пароля. По умолчанию 'password_change_done'.

form_class

Пользовательская форма «Смена пароля», которая должна принимать аргумент в виде ключевого слова user. Форма отвечает за фактическое изменение пароля пользователя. По умолчанию используется PasswordChangeForm.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

Контекст шаблона:

  • form: Форма смены пароля (см. form_class выше).
class PasswordChangeDoneView

Имя URL: password_change_done

Страница, отображаемая после того, как пользователь изменил свой пароль.

Атрибуты:

template_name

Полное имя шаблона для использования. По умолчанию registration/password_change_done.html, если не указано.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

class PasswordResetView

Имя URL: password_reset

Позволяет пользователю сбросить пароль путем генерации ссылки одноразового использования, которая может быть использована для сброса пароля, и отправки этой ссылки на зарегистрированный адрес электронной почты пользователя.

Это представление будет отправлять сообщение электронной почты, если выполняются следующие условия:

  • Указанный адрес электронной почты существует в системе.
  • Запрашиваемый пользователь активен (User.is_active равно True).
  • У запрашиваемого пользователя есть пароль, который можно использовать. Пользователям, отмеченным непригодным паролем (см. set_unusable_password()), не разрешается запрашивать сброс пароля, чтобы предотвратить злоупотребления при использовании внешнего источника аутентификации, например LDAP.

Если какое-либо из этих условий не выполняется, письмо не будет отправлено, но пользователь также не получит никакого сообщения об ошибке. Это предотвращает утечку информации к потенциальным злоумышленникам. Если вы хотите предоставить сообщение об ошибке в этом случае, вы можете подклассифицировать PasswordResetForm и использовать атрибут form_class.

Примечание

Имейте в виду, что отправка электронного письма требует дополнительного времени, поэтому вы можете быть уязвимы к атаке перечисления адресов электронной почты по времени из-за разницы между длительностью запроса сброса для существующего адреса электронной почты и длительностью запроса сброса для несуществующего адреса электронной почты. Чтобы уменьшить накладные расходы, вы можете использовать сторонний пакет, позволяющий отправлять электронные письма асинхронно, например django-mailer.

Атрибуты:

template_name

Полное имя шаблона, который будет использоваться для отображения формы сброса пароля. По умолчанию имеет значение registration/password_reset_form.html, если не указано.

form_class

Форма, которая будет использоваться для получения email пользователя для сброса пароля. По умолчанию имеет значение PasswordResetForm.

email_template_name

Полное имя шаблона, который будет использоваться для создания письма со ссылкой на сброс пароля. По умолчанию имеет значение registration/password_reset_email.html, если не указано.

subject_template_name

Полное имя шаблона, который будет использоваться для темы письма со ссылкой на сброс пароля. По умолчанию имеет значение registration/password_reset_subject.txt, если не указано.

token_generator

Экземпляр класса для проверки одноразовой ссылки. По умолчанию это будет default_token_generator, это экземпляр django.contrib.auth.tokens.PasswordResetTokenGenerator.

success_url

URL для перенаправления после успешного запроса на сброс пароля. По умолчанию 'password_reset_done'.

from_email

Действительный адрес электронной почты. По умолчанию Django использует DEFAULT_FROM_EMAIL.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

html_email_template_name

Полное имя шаблона, используемого для генерации многокомпонентного письма text/html со ссылкой для сброса пароля. По умолчанию письмо в формате HTML не отправляется.

Словарь контекстных данных, которые будут доступны в шаблоне письма. Его можно использовать для переопределения значений контекста шаблона по умолчанию, перечисленных ниже, например domain.

Контекст шаблона:

  • form: Форма (см. form_class выше) для сброса пароля пользователя.

Контекст шаблона электронной почты:

  • email: Псевдоним для user.email
  • user: Текущий User, в соответствии с полем формы email. Только активные пользователи могут сбрасывать свои пароли (User.is_active is True).
  • site_name: Псевдоним для site.name. Если у вас не установлен фреймворк сайта, это значение будет установлено в значение request.META['SERVER_NAME']. Подробнее о сайтах смотрите Структура «сайтов».
  • domain: Псевдоним для site.domain. Если у вас не установлен фреймворк сайта, то будет установлено значение request.get_host().
  • protocol: http или https
  • uid: Первичный ключ пользователя, закодированный в base 64.
  • token: Токен для проверки того, что ссылка сброса действительна.

Образец registration/password_reset_email.html (шаблон тела письма):

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

Тот же контекст шаблона используется для шаблона темы. Тема должна быть однострочной строкой обычного текста.

class PasswordResetDoneView

Имя URL: password_reset_done

Страница, отображаемая после того, как пользователь получил по электронной почте ссылку для сброса пароля. Это представление вызывается по умолчанию, если для PasswordResetView не задан явный URL success_url.

Примечание

Если указанный адрес электронной почты не существует в системе, пользователь неактивен или имеет недействительный пароль, пользователь все равно будет перенаправлен на этот вид, но письмо отправлено не будет.

Атрибуты:

template_name

Полное имя шаблона для использования. По умолчанию registration/password_reset_done.html, если не указано.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

class PasswordResetConfirmView

Имя URL: password_reset_confirm

Представляет форму для ввода нового пароля.

Ключевые аргументы из URL:

  • uidb64: Идентификатор пользователя, закодированный в base 64.
  • token: Токен для проверки правильности пароля.

Атрибуты:

template_name

Полное имя шаблона для отображения представления подтверждения пароля. Значение по умолчанию — registration/password_reset_confirm.html.

token_generator

Экземпляр класса для проверки пароля. По умолчанию это будет default_token_generator, это экземпляр django.contrib.auth.tokens.PasswordResetTokenGenerator.

post_reset_login

Булево значение, указывающее, следует ли автоматически аутентифицировать пользователя после успешного сброса пароля. По умолчанию имеет значение False.

post_reset_login_backend

Пунктирный путь к бэкенду аутентификации, который будет использоваться при аутентификации пользователя, если post_reset_login является True. Требуется, только если у вас настроено несколько AUTHENTICATION_BACKENDS. По умолчанию используется None.

form_class

Форма, которая будет использоваться для установки пароля. По умолчанию имеет значение SetPasswordForm.

success_url

URL для перенаправления после сброса пароля. По умолчанию 'password_reset_complete'.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

reset_url_token

Параметр токена, отображаемый как компонент URL-адресов сброса пароля. По умолчанию имеет значение 'set-password'.

Контекст шаблона:

  • form: Форма (см. form_class выше) для установки пароля нового пользователя.
  • validlink: Булево, истинно, если ссылка (комбинация uidb64 и token) действительна или еще не использована.
class PasswordResetCompleteView

Имя URL: password_reset_complete

Представляет представление, которое информирует пользователя о том, что пароль был успешно изменен.

Атрибуты:

template_name

Полное имя шаблона для отображения представления. По умолчанию имеет значение registration/password_reset_complete.html.

Словарь контекстных данных, которые будут добавлены к контекстным данным по умолчанию, переданным в шаблон.

Вспомогательные функции¶

redirect_to_login(next, login_url=None, redirect_field_name=‘next’

Перенаправляет на страницу входа в систему, а затем обратно на другой URL после успешного входа.

Требуемые аргументы:

  • next: URL для перенаправления после успешного входа в систему.

Дополнительные аргументы:

  • login_url: URL страницы входа в систему для перенаправления. По умолчанию settings.LOGIN_URL, если не указан.
  • redirect_field_name: Имя поля GET, содержащего URL для перенаправления после выхода из системы. Переопределяет next, если передан заданный GET параметр.

Встроенные формы¶

Если вы не хотите использовать встроенные представления, но желаете избежать необходимости писать формы для этой функциональности, система аутентификации предоставляет несколько встроенных форм, расположенных в django.contrib.auth.forms:

class AdminPasswordChangeForm

Форма, используемая в интерфейсе администратора для изменения пароля пользователя.

Принимает user в качестве первого позиционного аргумента.

class AuthenticationForm

Форма для входа пользователя в систему.

Принимает request в качестве первого позиционного аргумента, который сохраняется в экземпляре формы для использования подклассами.

confirm_login_allowed(user

По умолчанию AuthenticationForm отклоняет пользователей, чей флаг is_active установлен в False. Вы можете отменить это поведение с помощью пользовательской политики, чтобы определить, какие пользователи могут войти в систему. Сделайте это с помощью пользовательской формы, которая является подклассом AuthenticationForm и переопределяет метод confirm_login_allowed(). Этот метод должен вызывать ошибку ValidationError, если данный пользователь не может войти в систему.

Например, чтобы разрешить всем пользователям входить в систему независимо от статуса «активный»:

from django.contrib.auth.forms import AuthenticationForm

class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
    def confirm_login_allowed(self, user):
        pass

(В этом случае вам также необходимо использовать бэкенд аутентификации, который позволяет неактивным пользователям, например AllowAllUsersModelBackend).

Или разрешить вход только некоторым активным пользователям:

class PickyAuthenticationForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not user.is_active:
            raise ValidationError(
                _("This account is inactive."),
                code='inactive',
            )
        if user.username.startswith('b'):
            raise ValidationError(
                _("Sorry, accounts starting with 'b' aren't welcome here."),
                code='no_b_users',
            )
class PasswordChangeForm

Форма, позволяющая пользователю изменить свой пароль.

class PasswordResetForm

Форма для создания и отправки по электронной почте ссылки одноразового использования для сброса пароля пользователя.

send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None

Использует аргументы для отправки сообщения EmailMultiAlternatives. Может быть переопределено, чтобы настроить способ отправки письма пользователю.

Параметры:
  • subject_template_name – шаблон для темы.
  • email_template_name – шаблон для тела письма.
  • context – контекст, передаваемый в subject_template, email_template и html_email_template (если это не None).
  • from_email – электронная почта отправителя.
  • to_email – электронная почта подателя запроса.
  • html_email_template_name – шаблон для HTML-тела; по умолчанию None, в этом случае отправляется обычное текстовое письмо.

По умолчанию save() заполняет context теми же переменными, которые PasswordResetView передает своему почтовому контексту.

class SetPasswordForm

Форма, позволяющая пользователю изменить свой пароль без ввода старого пароля.

class UserChangeForm

Форма, используемая в интерфейсе администратора для изменения информации и разрешений пользователя.

class UserCreationForm

A ModelForm для создания нового пользователя.

Он имеет три поля: username (из модели пользователя), password1 и password2. Он проверяет соответствие password1 и password2, проверяет пароль с помощью validate_password() и устанавливает пароль пользователя с помощью set_password().

Данные аутентификации в шаблонах¶

Текущий зарегистрированный пользователь и его разрешения доступны в template context при использовании RequestContext.

Техничность

Технически, эти переменные становятся доступными в контексте шаблона, только если вы используете RequestContext и включен контекстный процессор 'django.contrib.auth.context_processors.auth'. Он находится в сгенерированном по умолчанию файле настроек. Подробнее см. в RequestContext docs.

Пользователи¶

При отображении шаблона RequestContext в переменной шаблона User хранится текущий зарегистрированный пользователь, либо экземпляр AnonymousUser, либо экземпляр {{ user }}:

{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
    <p>Welcome, new user. Please log in.</p>
{% endif %}

Эта контекстная переменная шаблона недоступна, если не используется RequestContext.

Права¶

Разрешения вошедшего в систему пользователя хранятся в переменной шаблона {{ perms }}. Это экземпляр django.contrib.auth.context_processors.PermWrapper, который является дружественным шаблону прокси разрешения.

Оценка одноатрибутного поиска {{ perms }} как булева является прокси для User.has_module_perms(). Например, чтобы проверить, есть ли у вошедшего пользователя какие-либо разрешения в приложении foo:

Оценка двухуровневого атрибута поиска как булева является прокси для User.has_perm(). Например, чтобы проверить, есть ли у вошедшего пользователя разрешение foo.add_vote:

{% if perms.foo.add_vote %}

Вот более полный пример проверки разрешений в шаблоне:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.add_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.add_driving %}
        <p>You can drive!</p>
    {% endif %}
{% else %}
    <p>You don't have permission to do anything in the foo app.</p>
{% endif %}

Можно также искать разрешения по операторам {% if in %}. Например:

{% if 'foo' in perms %}
    {% if 'foo.add_vote' in perms %}
        <p>In lookup works, too.</p>
    {% endif %}
{% endif %}

Управление пользователями в админке¶

Если у вас установлены и django.contrib.admin, и django.contrib.auth, администратор предоставляет удобный способ просмотра и управления пользователями, группами и разрешениями. Пользователи могут быть созданы и удалены, как и любая модель Django. Группы могут быть созданы, а разрешения могут быть назначены пользователям или группам. Журнал пользовательских правок моделей, сделанных в админке, также сохраняется и отображается.

Создание пользователей¶

Вы должны увидеть ссылку на «Пользователи» в разделе «Auth» на главной странице индекса администратора. Страница администратора «Добавить пользователя» отличается от стандартных страниц администратора тем, что она требует выбора имени пользователя и пароля, прежде чем вы сможете редактировать остальные поля пользователя.

Также обратите внимание: если вы хотите, чтобы учетная запись пользователя могла создавать пользователей с помощью сайта Django admin, вам нужно дать ей разрешение на добавление пользователей и изменение пользователей (т.е. разрешения «Добавить пользователя» и «Изменить пользователя»). Если у учетной записи есть разрешение на добавление пользователей, но нет разрешения на их изменение, эта учетная запись не сможет добавлять пользователей. Почему? Потому что если у вас есть разрешение на добавление пользователей, у вас есть возможность создавать суперпользователей, которые, в свою очередь, могут изменять других пользователей. Поэтому Django требует разрешения на добавление и изменение в качестве небольшой меры безопасности.

Вдумчиво отнеситесь к тому, как вы позволяете пользователям управлять разрешениями. Если вы дадите не суперпользователю возможность редактировать пользователей, это в конечном итоге будет равносильно предоставлению ему статуса суперпользователя, поскольку он сможет повышать разрешения пользователей, включая себя!

Изменение паролей¶

Пароли пользователей не отображаются в админке (и не хранятся в базе данных), но отображаются password storage details. В отображение этой информации включена ссылка на форму смены пароля, которая позволяет администраторам изменять пароли пользователей.

  • Назад
  • Обзор: Django
  • Далее

В данном руководстве мы продемонстрируем вам систему входа пользователя на ваш сайт используя его собственный аккаунт. Кроме того, мы покажем как реализовать контроль того, что может видеть и делать пользователь, в зависимости от того, залогинен он, или нет, а также имеет ли он соответствующий уровень прав доступа (permissions). Для того чтобы продемонстрировать все это, мы расширим LocalLibrary, добавив страницы для входа/выхода, а также страницы просмотра/редактирования книг, специфические для пользователя и персонала.

Требования: Завершить изучение предыдущих тем руководства, включая Руководство Django Часть 7: Работа с сессиями.
Цель: Понимать как настроить и использовать механизм аутентификации пользователя и разграничений прав доступа.

Обзор

Django предоставляет систему аутентификации и авторизации («permission») пользователя, реализованную на основе фреймворка работы с сессиями, который мы рассматривали в предыдущей части. Система аутентификации и авторизации позволяет вам проверять учётные данные пользователей и определять какие действия какой пользователь может выполнять. Данный фреймворк включает в себя встроенные модели для Пользователей и Групп (основной способ применения прав доступа для более чем одного пользователя), непосредственно саму систему прав доступа (permissions)/флаги, которые определяют может ли пользователь выполнить задачу, с какой формой и отображением для авторизованных пользователей, а так же получить доступ к контенту с ограниченным доступом.

Примечание: В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth).

В данном разделе руководства мы покажем вам реализацию аутентификации пользователя на сайте LocalLibrary, создание страниц входа/выхода, добавления разграничения доступа (permissions) к вашим моделям, а также продемонстрируем контроль за доступом к некоторым страницам. Мы будем использовать аутентификацию/авторизацию для показа пользователям и сотрудникам библиотеки, списков книг, которые были взяты на прокат.

Система аутентификации является очень гибкой и позволяет вам формировать свои собственные URL-адреса, формы, отображения, а также шаблоны страниц, если вы пожелаете, с нуля, через простой вызов функций соответствующего API для авторизации пользователя. Тем не менее, в данной статье мы будем использовать «встроенные» в Django методы отображений и форм аутентификации, а также методы построения страниц входа и выхода. Нам все ещё необходимо создавать шаблоны страниц, но это будет достаточно несложно.

Мы покажем вам как реализовать разграничение доступа (permissions), а также выполнять соответствующую проверку статусов авторизации и прав доступа, в отображениях, и в шаблонах страниц.

Подключение аутентификации

Аутентификация была подключена автоматически когда мы создали скелет сайта (в части 2), таким образом на данный момент вам ничего не надо делать.

Примечание: Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды django-admin startproject. Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду python manage.py migrate.

Соответствующие настройки сделаны в параметрах INSTALLED_APPS и MIDDLEWARE файла проекта (locallibrary/locallibrary/settings.py), как показано ниже:

INSTALLED_APPS = [
    ...
    'django.contrib.auth',  # Фреймворк аутентификации и моделей по умолчанию.
    'django.contrib.contenttypes',  # Django контент-типовая система (даёт разрешения, связанные с моделями).
    ....

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',  # Управление сессиями между запросами
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',  # Связывает пользователей, использующих сессии, запросами.
    ....

Создание пользователей и групп

Вы уже создали своего первого пользователя когда мы рассматривали Административная панель сайта Django в части 4 (это был суперпользователь, созданный при помощи команды python manage.py createsuperuser). Наш суперпользователь уже авторизован и имеет все необходимые уровни доступа к данным и функциям, таким образом нам необходимо создать тестового пользователя для отработки соответствующей работы сайта. В качестве наиболее быстрого способа, мы будем использовать административную панель сайта для создания соответствующих групп и аккаунтов locallibrary.

Примечание: вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта).

from django.contrib.auth.models import User

# Создайте пользователя и сохраните его в базе данных
user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword')

# Обновите поля и сохраните их снова
user.first_name = 'John'
user.last_name = 'Citizen'
user.save()

Ниже мы создадим группу, а затем пользователя. Несмотря на то, что у нас пока нет никаких разрешений для добавления к нашей библиотеке каких-либо членов, если мы захотим это сделать в будущем, то будет намного проще добавлять их к уже созданной группе, с заданной аутентификацией.

Запустите сервер разработки и перейдите к административной панели вашего сайта (http://127.0.0.1:8000/admin/). Залогиньтесь на сайте при помощи параметров (имя пользователя и пароля) аккаунта суперпользователя. Самая «верхняя» страница панели Администратора показывает все наши модели. Для того, чтобы увидеть записи в разделе Authentication and Authorisation вы можете нажать на ссылку Users, или Groups.

Admin site - add groups or users

В первую очередь, в качестве нового члена нашего сайта, давайте создадим новую группу.

  1. Нажмите на кнопку Add (Добавить) (рядом с Group) и создайте новую группу; для данной группы введите Name (Имя) «Library Members».
    Admin site - add group
  2. Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку SAVE (Сохранить) (вы перейдёте к списку групп).

Теперь давайте создадим пользователя:

  1. Перейдите обратно на домашнюю страницу административной панели
  2. Для перехода к диалогу добавления пользователя нажмите на кнопку Add, соответствующую строке Users (Пользователи).
    Admin site - add user pt1
  3. Введите соответствующие Username (имя пользователя) и Password/Password confirmation (пароль/подтверждение пароля) для вашего тестового пользователя
  4. Нажмите SAVE для завершения процесса создания пользователя.
    Административная часть сайта создаст нового пользователя и немедленно перенаправит вас на страницу Change user (Изменение параметров пользователя) где вы можете, соответственно, изменить ваш username, а кроме того добавить информацию для дополнительных полей модели User. Эти поля включают в себя имя пользователя, фамилию, адрес электронной почты, статус пользователя, а также соответствующие параметры доступа (может быть установлен только флаг Active). Ниже вы можете определить группу для пользователя и необходимые параметры доступа, а кроме того, вы можете увидеть важные даты, относящиеся к пользователю (дату подключения к сайту и дату последнего входа).
    Admin site - add user pt2
  5. В разделе Groups, из списка Доступные группы выберите группу Library Member, а затем переместите её в блок «Выбранные группы» (нажмите стрелку-«направо», находящуюся между блоками).
    Admin site - add user to group
  6. Больше нам не нужно здесь нечего делать, просто нажмите «Save»(Сохранить), и вы вернётесь к списку созданных пользователей.

Вот и все! Теперь у вас есть учётная запись «обычного члена библиотеки», которую вы сможете использовать для тестирования (как только добавим страницы, чтобы пользователи могли войти в систему).

Примечание: Попробуйте создать другого пользователя, например «Библиотекаря». Так же создайте группу «Библиотекарей» и добавьте туда своего только что созданного библиотекаря

Настройка представлений проверки

Django предоставляет почти все, что нужно для создания страниц аутентификации входа, выхода из системы и управления паролями из коробки. Это включает в себя url-адреса, представления (views) и формы,но не включает шаблоны — мы должны создать свой собственный шаблон!

В этом разделе мы покажем, как интегрировать систему по умолчанию в Сайт LocalLibrary и создать шаблоны. Мы поместим их в основные URL проекта.

Примечание: вы не должны использовать этот код, но вполне вероятно, что вы хотите, потому что это делает вещи намного проще. Вам почти наверняка потребуется изменить код обработки формы, если вы измените свою модель пользователя (сложная тема!) но даже в этом случае вы всё равно сможете использовать функции просмотра запасов.

**Примечание:**В этом случае мы могли бы разумно поместить страницы аутентификации, включая URL-адреса и шаблоны, в наше приложение каталога. Однако, если бы у нас было несколько приложений, было бы лучше отделить это общее поведение входа в систему и иметь его доступным на всем сайте, так что это то, что мы показали здесь!

Проектирование URLs

Добавьте следующее в нижней части проекта urls.py файл (locallibrary/locallibrary/urls.py) файл:

#Add Django site authentication urls (for login, logout, password management)
urlpatterns += [
    path('accounts/', include('django.contrib.auth.urls')),
]

Перейдите по http://127.0.0.1:8000/accounts/ URL (обратите внимание на косую черту!), Django покажет ошибку, что он не смог найти этот URL, и перечислить все URL, которые он пытался открыть. Из этого вы можете увидеть URL-адреса, которые будут работать, например:

Примечание: Примечание. Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов. Вам не нужно реализовывать что-либо ещё — приведённое выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса.

Примечание:

accounts/ login/ [name='login']
accounts/ logout/ [name='logout']
accounts/ password_change/ [name='password_change']
accounts/ password_change/done/ [name='password_change_done']
accounts/ password_reset/ [name='password_reset']
accounts/ password_reset/done/ [name='password_reset_done']
accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/ reset/done/ [name='password_reset_complete']

Теперь попробуйте перейти к URL-адресу входа (http://127.0.0.1:8000/accounts/login/). Это приведёт к сбою снова, но с ошибкой, сообщающей вам, что нам не хватает требуемого шаблона (registration / login.html) в пути поиска шаблона. Вы увидите следующие строки, перечисленные в жёлтом разделе вверху:

Exception Type:    TemplateDoesNotExist
Exception Value:    registration/login.html

Следующий шаг — создать каталог регистрации в пути поиска, а затем добавить файл login.html.

Каталог шаблонов

URL-адреса (и неявные представления), которые мы только что добавили, ожидают найти связанные с ними шаблоны в каталоге / регистрации / где-то в пути поиска шаблонов.

Для этого сайта мы разместим наши HTML-страницы в каталоге templates / registration /. Этот каталог должен находиться в корневом каталоге проекта, то есть в том же каталоге, что и в каталоге и папках locallibrary). Создайте эти папки сейчас.

Примечание: ваша структура папок теперь должна выглядеть как показано внизу:
locallibrary (django project folder)
|_catalog
|_locallibrary
|_templates (new)
|_registration

Чтобы сделать эти директории видимыми для загрузчика шаблонов (т. е. помещать этот каталог в путь поиска шаблона) откройте настройки проекта (/locallibrary/locallibrary/settings.py), и обновите в секции TEMPLATES строку 'DIRS' как показано.

TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        ...

Шаблон аутентификации

Предупреждение: Важно: Шаблоны аутентификации, представленные в этой статье, являются очень простой / слегка изменённой версией шаблонов логина демонстрации Django. Возможно, вам придётся настроить их для собственного использования!

Создайте новый HTML файл, названный /locallibrary/templates/registration/login.html. дайте ему следующее содержание:

{% extends "base_generic.html" %}

{% block content %}

{% if form.errors %}
  <p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
  {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
  {% else %}
    <p>Please login to see this page.</p>
  {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>

<tr>
  <td>{{ form.username.label_tag }}</td>
  <td>{{ form.username }}</td>
</tr>

<tr>
  <td>{{ form.password.label_tag }}</td>
  <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

Этот шаблон имеет сходство с тем, что мы видели раньше — он расширяет наш базовый шаблон и переопределяет блок контента. Остальная часть кода — это довольно стандартный код обработки формы, о котором мы поговорим в следующем учебном пособии. Все, что вам нужно знать, это показ формы, в которой вы можете ввести своё имя пользователя и пароль, а если вы введёте недопустимые значения, вам будет предложено ввести правильные значения, когда страница обновится.

Перейдите на страницу входа (http://127.0.0.1:8000/accounts/login/) когда вы сохраните свой шаблон, и вы должны увидеть что-то наподобие этого:

Library login page v1

Если ваша попытка войти в систему будет успешной, вы будете перенаправлены на другую страницу (по умолчанию это будет http://127.0.0.1:8000/accounts/profile/). Проблема здесь в том, что по умолчанию Django ожидает, что после входа в систему вы захотите перейти на страницу профиля, что может быть или не быть. Поскольку вы ещё не определили эту страницу, вы получите ещё одну ошибку!

Откройте настройки проекта (/locallibrary/locallibrary/settings.py) и добавьте текст ниже. Теперь, когда вы входите в систему, вы по умолчанию должны перенаправляться на домашнюю страницу сайта.

# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'

Шаблон выхода

Если вы перейдёте по URL-адресу выхода (http://127.0.0.1:8000/accounts/logout/), то увидите странное поведение — ваш пользователь наверняка выйдет из системы, но вы попадёте на страницу выхода администратора. Это не то, что вам нужно, хотя бы потому, что ссылка для входа на этой странице приведёт вас к экрану входа в систему администратора. (и это доступно только для пользователей, у которых есть разрешение is_staff).

Создайте и откройте /locallibrary/templates/registration/logged_out.html. Скопируйте текст ниже:

{% extends "base_generic.html" %}

{% block content %}
<p>Logged out!</p>

<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}

Этот шаблон очень прост. Он просто отображает сообщение, информирующее вас о том, что вы вышли из системы, и предоставляет ссылку, которую вы можете нажать, чтобы вернуться на экран входа в систему. Если вы снова перейдёте на страницу выхода из системы, вы увидите эту страницу:

Library logout page v1

Шаблон сброса пароля

Система сброса пароля по умолчанию использует электронную почту, чтобы отправить пользователю ссылку на сброс. Вам необходимо создать формы, чтобы получить адрес электронной почты пользователя, отправить электронное письмо, разрешить им вводить новый пароль и отметить, когда весь процесс будет завершён.

В качестве отправной точки можно использовать следующие шаблоны.

Форма сброса пароля

Это форма, используемая для получения адреса электронной почты пользователя (для отправки пароля для сброса пароля). Создайте /locallibrary/templates/registration/password_reset_form.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}
{% block content %}

<form action="" method="post">{% csrf_token %}
    {% if form.email.errors %} {{ form.email.errors }} {% endif %}
        <p>{{ form.email }}</p>
    <input type="submit" class="btn btn-default btn-lg" value="Reset password" />
</form>

{% endblock %}

Сброс пароля

Эта форма отображается после того, как ваш адрес электронной почты будет собран. Создайте /locallibrary/templates/registration/password_reset_done.html, и дайте ему следующее содержание:

{% extends "base_generic.html" %}
{% block content %}
<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
{% endblock %}

Сброс пароля по email

Этот шаблон предоставляет текст электронной почты HTML, содержащий ссылку на сброс, которую мы отправим пользователям. Создайте /locallibrary/templates/registration/password_reset_email.html и дайте ему следующее содержание:

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

Подтверждение на сброс пароля

На этой странице вы вводите новый пароль после нажатия ссылки в электронном письме с возвратом пароля. Создайте /locallibrary/templates/registration/password_reset_confirm.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}

{% block content %}

    {% if validlink %}
        <p>Please enter (and confirm) your new password.</p>
        <form action="" method="post">
            {% csrf_token %}
            <table>
                <tr>
                    <td>{{ form.new_password1.errors }}
                        <label for="id_new_password1">New password:</label></td>
                    <td>{{ form.new_password1 }}</td>
                </tr>
                <tr>
                    <td>{{ form.new_password2.errors }}
                        <label for="id_new_password2">Confirm password:</label></td>
                    <td>{{ form.new_password2 }}</td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="Change my password" /></td>
                </tr>
            </table>
        </form>
    {% else %}
        <h1>Password reset failed</h1>
        <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
    {% endif %}

{% endblock %}

Сброс пароля завершён

Это последний шаблон сброса пароля, который отображается, чтобы уведомить вас о завершении сброса пароля. Создайте /locallibrary/templates/registration/password_reset_complete.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}
{% block content %}

<h1>The password has been changed!</h1>
<p><a href="{% url 'login' %}">log in again?</a></p>

{% endblock %}

Тестирование новых страниц аутентификации

Теперь, когда вы добавили конфигурацию URL и создали все эти шаблоны, теперь страницы аутентификации должны работать! Вы можете протестировать новые страницы аутентификации, попытавшись войти в систему, а затем выйдите из учётной записи суперпользователя, используя эти URL-адреса:

  • http://127.0.0.1:8000/accounts/login/
  • http://127.0.0.1:8000/accounts/logout/

Вы сможете проверить функцию сброса пароля по ссылке на странице входа. Имейте в виду, что Django отправляет только сбросные электронные письма на адреса (пользователи), которые уже хранятся в его базе данных!

Примечание: Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть ещё не будет работать. Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли).

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Для получения дополнительной информации см. Отправка email (Django docs).

Тестирование проверки подлинности пользователей

В этом разделе мы рассмотрим, что мы можем сделать, чтобы выборочно контролировать контент, который видят пользователи, на основе того, вошли ли они в систему или нет.

Тестирование в шаблонах

Вы можете получить информацию о текущем зарегистрированном пользователе в шаблонах с переменной шаблона {{user}} (это добавляется в контекст шаблона по умолчанию при настройке проекта, как и в нашем скелете).

Обычно вы сначала проверяете переменную шаблона {{user.is_authenticated}}, чтобы определить, имеет ли пользователь право видеть конкретный контент. Чтобы продемонстрировать это, мы обновим нашу боковую панель, чтобы отобразить ссылку «Вход», если пользователь вышел из системы, и ссылку «Выход», если он вошёл в систему.

Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и скопируйте следующий текст в sidebar блок непосредственно перед тегом шаблона endblock.

  <ul class="sidebar-nav">

    ...

   {% if user.is_authenticated %}
     <li>User: {{ user.get_username }}</li>
     <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
   {% else %}
     <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
   {% endif %}
  </ul>

Как вы можете видеть, мы используем теги шаблона if-else-endif для условного отображения текста на основе того, является ли {{user.is_authenticated}} истинным. Если пользователь аутентифицирован, мы знаем, что у нас есть действительный пользователь, поэтому мы вызываем {{user.get_username}}, чтобы отобразить их имя.

Мы создаём URL-адрес для входа и выхода из системы, используя тег шаблона URL-адреса и имена соответствующих конфигураций URLs. Также обратите внимание на то, как мы добавили ?next={{request.path}} в конец URLs. Это означает, что следующий URL-адрес содержит адрес (URL) текущей страницы, в конце связанного URL-адреса. После того, как пользователь успешно выполнил вход в систему, представления будут использовать значение «next» чтобы перенаправить пользователя обратно на страницу, где они сначала нажали ссылку входа / выхода из системы.

Примечание: Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу.

Тестирование в представлениях

Если вы используете функциональные представления, самым простым способом ограничить доступ к вашим функциям является применение login_required декоратор к вашей функции просмотра, как показано ниже. Если пользователь вошёл в систему, ваш код просмотра будет выполняться как обычно. Если пользователь не вошёл в систему, это перенаправит URL-адрес входа, определённый в настройках проекта. (settings.LOGIN_URL), передав текущий абсолютный путь в качестве next параметра URL. Если пользователю удастся войти в систему, они будут возвращены на эту страницу, но на этот раз аутентифицированы.

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

Примечание: Вы можете сделать то же самое вручную, путём тестирования request.user.is_authenticated, но декоратор намного удобнее!

Аналогичным образом, самый простой способ ограничить доступ к зарегистрированным пользователям в ваших представлениях на основе классов — это производные от LoginRequiredMixin. Вы должны объявить этот mixin сначала в списке суперкласса, перед классом основного представления.

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    ...

Это имеет такое же поведение при переадресации, что и login_required декоратор. Вы также можете указать альтернативное местоположение для перенаправления пользователя, если он не аутентифицирован (login_url), и имя параметра URL вместо «next» , чтобы вставить текущий абсолютный путь (redirect_field_name).

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

Для получения дополнительной информации ознакомьтесь с Django docs here.

Пример — перечисление книг текущего пользователя

Теперь, когда мы знаем, как ограничить страницу определённому пользователю, создайте представление о книгах, которые заимствовал текущий пользователь.

К сожалению, у нас пока нет возможности пользователям использовать книги! Поэтому, прежде чем мы сможем создать список книг, мы сначала расширим BookInstance модель для поддержки концепции заимствования и использования приложения Django Admin для заимствования ряда книг нашему тестовому пользователю.

Модели

Прежде всего, мы должны предоставить пользователям возможность кредита на BookInstance (у нас уже есть status и due_back дата, но у нас пока нет связи между этой моделью и пользователем. Мы создадим его с помощью поля ForeignKey (один ко многим). Нам также нужен простой механизм для проверки того, просрочена ли заёмная книга.

Откройте catalog/models.py, и импортируйте модель User из django.contrib.auth.models (добавьте это чуть ниже предыдущей строки импорта в верхней части файла, так User доступен для последующего кода, что позволяет использовать его):

from django.contrib.auth.models import User

Затем добавьте поле borrower в модель BookInstance:

borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)

Пока мы здесь, давайте добавим свойство, которое мы можем вызвать из наших шаблонов, чтобы указать, просрочен ли конкретный экземпляр книги. Хотя мы могли бы рассчитать это в самом шаблоне, использование свойства, как показано ниже, будет намного более эффективным. Добавьте это где-нибудь в верхней части файла:

from datetime import date

Теперь добавьте следующее определение свойства внутри класса BookInstance:

@property
def is_overdue(self):
    if self.due_back and date.today() > self.due_back:
        return True
    return False

Примечание: Примечание. Сначала мы проверим, является ли due_back пустым, прежде чем проводить сравнение. Пустое поле due_back заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали!

Теперь, когда мы обновили наши модели, нам нужно будет внести новые изменения в проект, а затем применить эти миграции:

python3 manage.py makemigrations
python3 manage.py migrate

Admin

Теперь откройте каталог catalog/admin.py, и добавьте поле borrower в класс BookInstanceAdmin , как в list_display , так и в полях fieldsets , как показано ниже. Это сделает поле видимым в разделе Admin, так что мы можем при необходимости назначить User в BookInstance.

@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    list_display = ('book', 'status', 'borrower', 'due_back', 'id')
    list_filter = ('status', 'due_back')

    fieldsets = (
        (None, {
            'fields': ('book','imprint', 'id')
        }),
        ('Availability', {
            'fields': ('status', 'due_back','borrower')
        }),
    )

Займите несколько книг

Теперь, когда возможно кредитовать книги конкретному пользователю, зайдите и заработайте на нескольких записей в BookInstance. Установите borrowed поле вашему тестовому пользователю, сделайте status «В займе» и установите сроки оплаты как в будущем, так и в прошлом.

Примечание: Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт!

Займ в представлении

Теперь мы добавим представление для получения списка всех книг, которые были предоставлены текущему пользователю. Мы будем использовать один и тот же общий класс, с которым мы знакомы, но на этот раз мы также будем импортировать и выводить из LoginRequiredMixin, так что только вошедший пользователь сможет вызвать это представление. Мы также решили объявить template_name, вместо того, чтобы использовать значение по умолчанию, потому что у нас может быть несколько разных списков записей BookInstance, с разными представлениями и шаблонами.

Добавьте следующее в catalog/views.py:

from django.contrib.auth.mixins import LoginRequiredMixin

class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
    """
    Generic class-based view listing books on loan to current user.
    """
    model = BookInstance
    template_name ='catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10

    def get_queryset(self):
        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')

Чтобы ограничить наш запрос только объектами BookInstance для текущего пользователя, мы повторно реализуем get_queryset(), как показано выше. Обратите внимание, что «o» это сохранённый код для «on loan» и мы сортируем по дате due_back, чтобы сначала отображались самые старые элементы.

URL-адрес для заёмных книг

Теперь откройте /catalog/urls.py и добавьте url() , указывая на приведённое выше представление (вы можете просто скопировать текст ниже в конец файла).

urlpatterns += [
    url(r'^mybooks/$', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
]

Шаблон для заёмных книг

Теперь все, что нам нужно сделать для этой страницы, — это добавить шаблон. Сначала создайте файл шаблона /catalog/templates/catalog/bookinstance_list_borrowed_user.html и дайте ему следующее содержание:

{% extends "base_generic.html" %}

{% block content %}
    <h1>Borrowed books</h1>

    {% if bookinstance_list %}
    <ul>

      {% for bookinst in bookinstance_list %}
      <li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
        <a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }})
      </li>
      {% endfor %}
    </ul>

    {% else %}
      <p>There are no books borrowed.</p>
    {% endif %}
{% endblock %}

Этот шаблон очень похож на тот, который мы создали ранее для объектов Book и Author. Единственное, что «новое» здесь, это то, что мы проверяем метод, который мы добавили в модель (bookinst.is_overdue) с целью использовать его для изменения цвета просроченных предметов.

Когда сервер разработки запущен, вы должны теперь иметь возможность просматривать список для зарегистрированного пользователя в своём браузере по адресу http://127.0.0.1:8000/catalog/mybooks/. Попробуйте это, когда ваш пользователь войдёт в систему и выйдет из системы (во втором случае вы должны быть перенаправлены на страницу входа в систему).

Добавить список на боковую панель

Последний шаг — добавить ссылку на эту новую страницу в sidebar. Мы поместим это в тот же раздел, где мы покажем другую информацию для зарегистрированного пользователя.

Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и добавьте выделенную строку из sidebar, как показано на рисунке.

 <ul class="sidebar-nav">
   {% if user.is_authenticated %}
   <li>User: {{ user.get_username }}</li>
   <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
   <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
   {% else %}
   <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
   {% endif %}
 </ul>

На что это похоже?

Когда любой пользователь войдёт в систему, он будет видеть ссылку «Мной позаимствовано (My Borrowed)» в боковой колонке, и список книг, показанных ниже (первая книга не имеет установленной даты, что является ошибкой, которую мы надеемся исправить в более позднем уроке!).

Library - borrowed books by user

Права доступа

Права доступа связаны с моделями и определяют операции, которые могут выполняться на экземпляре модели самим пользователем, у которого есть разрешение. По умолчанию Django автоматически даёт добавить, изменить, и удалить разрешения у всех моделей, которые позволяют пользователям с правом доступа выполнять связанные действия через администратора сайта. Вы можете определить свои собственные разрешения для моделей и предоставить их конкретным пользователям. Вы также можете изменить разрешения, связанные с разными экземплярами одной и той же модели. Тестирование разрешений в представлениях и шаблонах очень похоже на тестирование по статусу аутентификации (фактически, тестирование прав доступа также проверяет аутентификацию).

Модели

Определение разрешений выполняется в разделе моделей «class Meta» , используется permissions поле. Вы можете указать столько разрешений, сколько необходимо в кортеже, причём каждое разрешение определяется во вложенном кортеже, содержащем имя разрешения и отображаемое значение разрешения. Например, мы можем определить разрешение, позволяющее пользователю отметить, что книга была возвращена, как показано здесь:

class BookInstance(models.Model):
    ...
    class Meta:
        ...
        permissions = (("can_mark_returned", "Set book as returned"),)

Затем мы могли бы назначить разрешение группе «Библиотекарь» (Librarian) на сайте администратора.

Откройте catalog/models.py, и добавьте разрешение, как показано выше. Вам нужно будет повторно выполнить миграцию (вызвав python3 manage.py makemigrations и python3 manage.py migrate) для надлежащего обновления базы данных.

Шаблоны

Разрешения текущего пользователя хранятся в переменной шаблона, называемой {{ perms }}. Вы можете проверить, имеет ли текущий пользователь определённое разрешение, используя конкретное имя переменной в соответствующем приложении «Django» — например, {{ perms.catalog.can_mark_returned }} будет True если у пользователя есть это разрешение, а False — в противном случае. Обычно мы проверяем разрешение с использованием шаблона {% if %}, как показано в:

{% if perms.catalog.can_mark_returned %}
    <!-- We can mark a BookInstance as returned. -->
    <!-- Perhaps add code to link to a "book return" view here. -->
{% endif %}

Представления

Разрешения можно проверить в представлении функции, используя permission_required декоратор или в представлении на основе классов, используя PermissionRequiredMixin. шаблон и поведение такие же, как для аутентификации входа в систему, хотя, конечно, вы можете разумно добавить несколько разрешений.

Функция в представлении с декоратором:

from django.contrib.auth.decorators import permission_required

@permission_required('catalog.can_mark_returned')
@permission_required('catalog.can_edit')
def my_view(request):
    ...

Требуется разрешение mixin для представлений на основе классов.

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'catalog.can_mark_returned'
    # Or multiple permissions
    permission_required = ('catalog.can_mark_returned', 'catalog.can_edit')
    # Note that 'catalog.can_edit' is just an example
    # the catalog application doesn't have such permission!

Пример

Мы не будем обновлять LocalLibrary здесь; возможно, в следующем уроке!

Испытайте себя

Ранее в этой статье мы показали вам, как создать страницу для текущего пользователя, в которой перечислены книги, которые они заимствовали. Теперь задача состоит в том, чтобы создать аналогичную страницу, которая видна только для библиотекарей, которая отображает все книги, которые были заимствованы, и которая показывает имя каждого заёмщика.

Вы должны следовать той же схеме, что и для другого представления. Главное отличие состоит в том, что вам нужно ограничить представление только библиотекарями. Вы можете сделать это на основе того, является ли пользователь сотрудником (декоратор функции: staff_member_required, переменная шаблона: user.is_staff) но мы рекомендуем вам вместо этого использовать can_mark_returned разрешения и PermissionRequiredMixin, как описано в предыдущем разделе.

Предупреждение: Важно: Не забудьте использовать вашего суперпользователя для тестирования на основе разрешений (проверки разрешений всегда возвращают true для суперпользователей, даже если разрешение ещё не определено!). Вместо этого создайте пользователя-библиотекаря и добавьте необходимые возможности.

Когда вы закончите, ваша страница должна выглядеть примерно, как на скриншоте ниже.

All borrowed books, restricted to librarian

Подводим итоги

Отличная работа — теперь вы создали веб-сайт, на котором участники библиотеки могут входить в систему и просматривать собственный контент, и библиотекари (с правом доступа) могут просматривать все заёмные книги с их читателями. На данный момент мы все ещё просто просматриваем контент, но те же принципы и методы используются, когда вы хотите начать изменять и добавлять данные.

В следующей статье мы рассмотрим, как вы можете использовать формы Django для сбора пользовательского ввода, а затем начнём изменять некоторые из наших сохранённых данных.

Смотрите также

14.03.2012

Думаю, вы хотите, чтобы ваши сообщения об ошибках в заполняемых формах были на том же языке, что и сам сайт. Один из простых способов — это добавить следующий код в соответствующий forms.py. Затем формы надо будет наследовать не от forms.Form, а от MyForm (обратите внимание, ExampleForm, в примере ниже, наследуется от него).

class MyForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        for k, field in self.fields.items():
            if 'required' in field.error_messages:
                field.error_messages['required'] = u'Это поле обязательно!'

class ExampleForm(MyForm):
    title = forms.CharField(max_length=100, required=True, label=u'Название')

Полный список error_messages для различных типов полей можно увидеть, если просмотреть этот раздел: https://docs.djangoproject.com/en/1.3/ref/forms/fields/#built-in-field-classes

Вот что есть на данный момент:

required — показывается, если данное поле обязательно;
max_length — если превышено максимальное количество символов в символьном поле / в случае с файлами — длина имени файла;
min_length — если символов меньше, чем должно быть, в символьном поле;
invalid_choice — если выбран невозможный choice;
invalid — при неправильном email’е и прочем неправильном вводе данных;
max_value — если превышено числовое значение;
min_value — если значение меньше минимального числового ограничения;
max_digits — если превышено количество цифр в числе;
max_decimal_places — если превышено количество цифр после запятой;
max_whole_digits — если превышено количество цифр до запятой;
missing — если файл не найден;
empty — если файл пустой;
invalid_image — если изображение повреждено;
invalid_list  — если неправильный список choice’ов;
invalid_link — для URLField — вызывается, если данного url не существует.

Основано на примере с http://stackoverflow.com/questions/1481771/django-override-default-form-error-messages

django

Понравилась статья? Поделить с друзьями:
  • Django forms error class
  • Django forms custom error
  • Django form save error
  • Django form raise validation error
  • Django form is valid get error