Django 5 для начинающих

Прогресс по курсу:  9/1004

7.2 Использование системы аутентификации Django
4 из 7 шагов пройдено
0 из 11 баллов  получено

Приложение авторизации Django

Django автоматически устанавливает auth приложение при создании нового проекта. Посмотрите в mysite/settings.py в разделе INSTALLED_APPS, и вы увидите, auth что это одно из нескольких встроенных приложений, которые Django установил для нас:

Чтобы использовать встроенное auth приложение, нам нужно добавить его в наш urls.py файл проекта. Не забудьте добавить include вторую строку.

Я решил включить auth приложение в accounts/, но вы можете использовать любой шаблон URL, который хотите. Также мы изменим адрес нашего блога, с http://127.0.0.1:8000/blog/ на http://127.0.0.1:8000/:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls', namespace='blog')),
    path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
         name='django.contrib.sitemaps.views.sitemap'),
    path("accounts/", include("django.contrib.auth.urls")),  # new
]

Приложение auth, которое мы сейчас включили, предоставляет нам несколько представлений аутентификации и URL-адресов для управления входом в систему, выходом из системы и управлением паролями.

URL-адреса, предоставленные auth:

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 также есть связанные представления аутентификации. Это означает, что нам нужно только создать шаблон для использования каждого!

Страница авторизации

Давайте сделаем нашу страницу входа! Django по умолчанию будет искать в папке шаблонов, называемой registration шаблонами аутентификации. Шаблон входа назовем login.html.

Создайте новый каталог с именем registration в нашей папке шаблонов templates.

В итоге наша файловая структура шаблонов будет выглядеть так:

Затем вtemplates/registration/login.html добавьте следующий код:

{% extends "blog/base.html" %}
{% block title %} Login {% endblock %}
{% block content %}
    <h2> Login </h2>
    <form method="post">
        {{ form.as_p }}
        {% csrf_token %}
        <p><input type="submit" value="Login"></p>
    </form>
{% endblock %}

Это стандартная форма Django, использует метод POST для отправки данных и {% csrf_token %} тегов из соображений безопасности, а именно для предотвращения атаки CSRF.

Содержимое формы выводится между тегами абзаца благодаря, {{ form.as_p }} а затем мы добавляем кнопку LOGIN:

Перейдем по адресу http://127.0.0.1:8000/accounts/login/ и проверим работу:

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

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

Мы используем LOGIN_REDIRECT_URL настройку, чтобы указать этот маршрут.

Внизу файла settings.py добавьте следующее, чтобы перенаправить пользователя на домашнюю страницу:

LOGIN_REDIRECT_URL  =  "/"

А теперь давайте проверим, мы можем войти под данными суперпользователя, которые создавали в разделе 5.3.1 "Сайт администрирования".

Если мы правильно введем логин и пароль, мы будем перенаправлены на главную страницу. И если после этого мы перейдем в нашу админ-панель, http://127.0.0.1:8000/admin/, то мы увидим что никакой авторизации не требуется.

 

Выход

Но как выйти из системы? В настоящее время единственный вариант — зайти в панель администратора http://127.0.0.1:8000/admin/ и нажать на ссылку LOG OUT в правом верхнем углу:

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

Возможности auth уже предоставляют нам встроенный URL-адрес и представление для этого. Нам не нужно ничего отображать при выходе из системы, поэтому нет необходимости в шаблоне. Все, что мы действительно делаем после успешного запроса на «выход из системы», — это перенаправление на другую страницу.

Давайте отредактируем наш базовый шаблон, base.html и изменим часть кода нашего сайдбара:

.
..
...

<div id="sidebar">
    <h2>My blog</h2>
    <p>
        This is my blog.
        I've written {% total_posts %} posts so far.
    </p>
    <hr>
    {% if user.is_authenticated %}
        Hi {{ user.username }}!
    <form action="{% url 'logout' %}" method="post">
        {% csrf_token %}
        <a href="#" onclick="parentNode.submit();">Log Out</a>
    </form>
    {% else %}
        <p>You are not logged in</p>
        <a href="{% url 'login' %}">Log In</a>
    {% endif %}
    <hr>

    <h3>Latest posts</h3>
...
..
.

Начиная с версии Django 5, чтобы выйти из системы мы должны отправить  POST запрос. До этого можно было обойтись простым  GET запросом. Затем обновите settings.py нашу ссылку перенаправления, которая называется LOGOUT_REDIRECT_URL.

Добавьте его прямо рядом с нашей переадресацией входа, чтобы нижняя часть файла settings.py выглядела следующим образом:

LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/"

Теперь, если вы повторно посетите блог и войдете в систему, вы будете перенаправлены на новую домашнюю страницу, на которой есть ссылка Log Out для вошедших в систему пользователей:

Нажав на нее, вы вернетесь на домашнюю страницу со ссылкой Log In:

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

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

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


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

Увы, но на версии Django 5.0 и выше  удалили выход из системы по запросу GET. Описанным здесь путь выхода из системы в моем проекте не работает. В кой-то веки решил пятерку попробовать....

Not Found: /logout/
[25/Jan/2024 21:20:42] "GET /logout/ HTTP/1.1" 404 3525
Method Not Allowed (GET): /accounts/logout/

Решение проблемы:

pip3 uninstall Django
pip3 install Django==4.1.0

 Документация

@Евгений_Куликов, да, действительно в Django 5 теперь для выхода нужно отправлять POST запрос. Я думаю постараемся в ближайшее время перевести курс на 5 версию.

@Илья_Перминов, насколько верным является данное решение для Django 5?

<form method="post" action="{% url 'logout' %}">
    {% csrf_token %}
    <button type="submit">Log Out</button>
</form>

@Корнев_Степан, Не плохой, самый наверное будет простой в этом случае. Если нужно стилизовать как ссылку, можно и так отправлять запрос:

                        <form action="{% url 'logout' %}" method="post">
                            {% csrf_token %}
                            <input type="hidden"/>
                            <a href="#" onclick="parentNode.submit();">Выйти</a>
                        </form>

@Илья_Перминов, Понял, спасибо. А для чего здесь поле <input type="hidden"/>?

@Корнев_Степан, чтобы установить скрытое поле, скорее всего будет работать и без него, но у меня тогда валидатор в браузере начинает ругаться.

Странно, но у меня он не может найти шаблон:
DoesNotExist at /accounts/login/

Site matching query does not exist.

@Михаил, в конце шага https://stepik.org/lesson/973398/step/1?unit=980250 меняли имя сайта?

@Дмитрий_Селезнев, Исправил, спасибо. Не стал в тот момент менять, думал не пригодится

Как работает этот блок кода?
<form action="{% url 'logout' %}" method="post">
        {% csrf_token %}
        <a href="#" onclick="parentNode.submit();">Log Out</a> </form>
Правильно ли я понимаю, что при нажатии на кнопку "Log Out", выполняется функция "parentNode.submit();" (что это за функция) и тем самым мы передаем форму на обработку в "url 'logout" (accounts/logout/) методом POST? А параметр href принимает значение # для того, чтобы остаться на той же странице?

@Александр_Ёлшин, только не на кнопку, а на ссылку, для кнопки достаточно такого кода <button type="submit">Log Out</button>.

А функция parentNode.submit(); вызывает отправку для родительского элемента, в нашем случае для формы.

Остальное всё правильно.

Правильно ли я понимаю:

Приложение auth которое предустановлено в Джанго, имеет встроенный url "logout"

accounts/logout/ [name='logout'] и необходимости писать представление нет(используя этот url в шаблоне), или все таки лучше использовать функцию-представление для этого ? 

@Vladislav, да, правильно понимаете. Вот содержимое модуля django.contrib.auth.urls, который мы инклюдим:

from django.contrib.auth import views
from django.urls import path

urlpatterns = [
    path("login/", views.LoginView.as_view(), name="login"),
    path("logout/", views.LogoutView.as_view(), name="logout"),
    path(
        "password_change/", views.PasswordChangeView.as_view(), name="password_change"
    ),
    path(
        "password_change/done/",
        views.PasswordChangeDoneView.as_view(),
        name="password_change_done",
    ),
    path("password_reset/", views.PasswordResetView.as_view(), name="password_reset"),
    path(
        "password_reset/done/",
        views.PasswordResetDoneView.as_view(),
        name="password_reset_done",
    ),
    path(
        "reset/<uidb64>/<token>/",
        views.PasswordResetConfirmView.as_view(),
        name="password_reset_confirm",
    ),
    path(
        "reset/done/",
        views.PasswordResetCompleteView.as_view(),
        name="password_reset_complete",
    ),
]

https://github.com/django/django/blob/5.0/django/contrib/auth/urls.py

@Дмитрий_Селезнев

Спасибо за ответ

Кажется, я немного потерялся. Сначала мы создали шаблон "templates/registration/login.html". Потом мы проверяем "Перейдем по адресу http://127.0.0.1:8000/accounts/login/ и проверим работу:". Видим надпись "войти", форму и соответствующую кнопку. Потом мы редактируем "base", settings. Теперь по адресу http://127.0.0.1:8000/accounts/login/ видим 'login', форму и кнопку "login". 

Вопрос: откуда изначально взялась надпись "войти" и такая же кнопка?

@Сак_Валентин, Это все автоперевод в Chrome)) Даже не заметили. Сейчас поправим.

У меня почему-то не работают LOGIN_REDIRECT_URL = "/"  и  LOGOUT_REDIRECT_URL = "/". Пришлось их изменить на: 

LOGIN_REDIRECT_URL  =  "/blog"

LOGOUT_REDIRECT_URL  =  "/blog"

А вы изменили адрес блога, с http://127.0.0.1:8000/blog/ на http://127.0.0.1:8000/ ? В лекции есть urls.py где мы переделали адрес нашей страницы блога.

@Илья_Перминов, Видимо, я что-то пропустил. А не подскажете, как можно изменить адрес блога с http://127.0.0.1:8000/blog/ на http://127.0.0.1:8000/ ?

@Агаси_Мироян, у нас в urls было:

path('blog/', include('blog.urls', namespace='blog')),

А мы перенесли блог в корень адреса:

path('', include('blog.urls', namespace='blog')),

То есть на данном этапе наш urls проекта стал содержать следующее:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls', namespace='blog')),
    path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
         name='django.contrib.sitemaps.views.sitemap'),
    path("accounts/", include("django.contrib.auth.urls")),  # new
]

В самом начале этой лекции мы писали об этом. 

Изменен Илья Перминов

@Илья_Перминов, Спасибо большое, видимо усталость сказалась. Вы не представляете насколько неудобно было каждый раз при запуске сервера получать уведомление об ошибке и добавлять в браузере к url-адресу blog.