Декоратор login_required и класс LoginRequiredMixin

Курс по Django: https://stepik.org/a/183363

Архив проекта: 63_sitewomen.zip

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

Начнем с функций представлений. В файле women/views.py у нас имеется такая подходящая функция с именем about(), которая отвечает за страницу «О сайте». Чтобы закрыть ее от неавторизованных пользователей, достаточно декорировать ее декоратором login_required следующим образом:

@login_required
def about(request):
    ...

Если теперь запустить веб-сервер и попытаться перейти на эту страницу неавторизованному пользователю, то выполнится автоматическое перенаправление по адресу:

http://127.0.0.1:8000/accounts/login/?next=/about/

Обратите внимание на появление параметра next. Благодаря ему, после успешной авторизации мы сразу перейдем к закрытой странице «О сайте». Но на данный момент у нас другая проблема. Фреймворк Django выполняет автоматическое перенаправление по несуществующему URL-адресу. Поправить это очень просто. Вспомним об еще одном параметре LOGIN_URL, который определяет адрес страницы с формой авторизации. В файле settings.py пропишем его следующим образом:

LOGIN_URL = 'users:login'

Теперь, при заходе на страницу «О сайте» нам открывается форма авторизации. И фреймворк Django автоматически добавляет к URL-адресу параметр next. Вводим верные логин/пароль. И заветная страница отображается в браузере пользователя. Вот так с помощью декоратора login_required можно ограничивать доступ к отдельным страницам сайта.

Другой вариант перенаправления при доступе к закрытой странице можно определять с помощью параметра login_url самого декоратора:

@login_required(login_url='/admin/')

Произойдет перенаправление к старице админ-панели. Причем, приоритет этого параметра выше, чем LOGIN_URL.

Класс миксин LoginRequiredMixin

Когда мы имеем дело с классами представлений, то здесь вместо декоратора login_required используется класс минксинов LoginRequiredMixin. О миксинах мы с вами уже говорили, когда создавали свой класс DataMixin. В данном случае LoginRequiredMixin добавляет новый функционал к классу представления, ограничивая доступ к странице неавторизованным пользователям. Давайте его пропишем для класса AddPage, предполагая, что новые статьи могут добавлять только зарегистрированные пользователи:

class AddPage(LoginRequiredMixin, DataMixin, CreateView):
    ...

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

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

login_url = '/admin/'

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

Добавление авторства статей

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

author = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, related_name='posts', null=True, default=None)

Обратите внимание, мы обращаемся к модели User с помощью функции get_user_model(). Это считается предпочтительной практикой для фреймворка Django. Далее, прописываем параметр on_delete с флагом SET_NULL, то есть, при удалении пользователя поле author будет содержать значение NULL. Остальные параметры вам уже хорошо известны.

Так как модель изменилась, то нам нужно создать и применить миграции:

python manage.py makemigrations
python manage.py migrate  

Все, таблица women обновлена и в ней появилось новое поле author_id со значениями NULL.

Осталось только заполнять это поле в момент добавления статьи. Для этого перейдем в файл women/views.py и в класс AddPage добавим метод form_valid():

    def form_valid(self, form):
        w = form.save(commit=False)
        w.author = self.request.user
        return super().form_valid(form)

Смотрите, мы здесь обращаемся к форме и вызываем у нее метод save() с параметром commit=False. Благодаря ему данные не записываются в таблицу БД, а формируются только в памяти. В результате ссылка w будет указывать на объект модели Women текущей записи. Меняем в этом объекте атрибут author, присваивая ему объект user текущего пользователя. Далее, измененный объект w будет автоматически сохранен в таблице БД.

Посмотрим, как это будет работать. Откроем страницу добавления записи. Введем произвольные данные и видим, что в поле author_id таблицы women появилось значение 1. Это как раз идентификатор авторизованного суперпользователя.

Ну и раз у нас каждая статья связана с пользователем, то отобразим его username в списке статей. Откроем файл index.html и изменим строчку при отображении названий категорий:

<p class="first">Категория: {{p.cat.name}} | автор: {{p.author.username|default:"неизвестен"}}</p>

Теперь на странице дополнительно отображается ее автор, если он известен.

Курс по Django: https://stepik.org/a/183363

Видео по теме