Django 36. Добавление постов пользователем
В этом посте мы добавим группу пользователей "Автор". Реализуем форму добавления постов на стороне сайта, а также я расскажу о нюансах использования визуального редактора CKeditor5.
Дополнительные материалы
Для скачивания материалов необходимо войти или зарегистрироваться
Файлы также можно получить в Telegram-боте по коду: 517311
Реклама
Продолжаем развивать наш блог. Мы с вами реализовали регистрацию и создали профиль пользователя, теперь реализуем добавление постов не только Администратором, но и Авторами.
Создать форму для добавления постов, создания новых категорий или загрузки файлов - задача нехитрая. Куда сложнее дать авторам возможность редактировать и при необходимости удалять уже созданные ими ранее посты.
В этом и нескольких последующих постах мы подробно рассмотрим процесс создания страницы с формами, а также приспособим личный кабинет под нужды авторов.
Библиотека pytils.
В модели поста есть поле slug
. Подробнее о нём я писал в постах "Django 16. Модель категорий" и "Django 20. Модель поста".
Когда мы добавляем пост через панель администратора, его заголовок преобразуется в текст на латинице автоматически.
В случае с добавлением поста на стороне сайта такой возможности нет, поэтому мы прибегнем к помощи библиотеки pytils, в которой есть функция slugify, переводящая текст из кириллицы в латиницу.
Установим библиотеку командой:
pip install pytils
И добавим её в requirements.txt
:
pytils~=0.4.1
Группа пользователей "Автор".
Для того чтобы создавать посты могли только авторы, а не все пользователи, необходимо создать такую группу в панели администратора.
Откроем панель администратора и в блоке "Пользователи и группы" откроем раздел Группы.
Нажимаем кнопку "Добавить".
В поле "Имя" вводим название группы, в нашем случае - "Автор".
На данный момент никакие права не выдаём, нам нужна только группа пользователей.
Нажимаем "Сохранить".
Готово. Теперь у нас есть группа "Авторы".
Для добавления пользователя в эту группу необходимо открыть раздел "Пользователи", выбрать нужного пользователя и в блоке с выбором группы добавить группу "Автор" в выбранные.
Форма добавления поста.
Нам нужно создать форму модели для добавления нового поста.
Откроем файл forms.py
в приложении user_app
. Создадим новый класс AddPostByAuthorForm
, унаследованный от forms.ModelForm
.
Ранее мы прописывали каждое поле с его типом и виджетом. В этот раз мы поступим иначе: получим поля из модели и в конструкторе класса __init__
проитерируемся по списку полей, добавляя к атрибутам поля нужный bootstrap
-класс.
После цикла, дополнительно пропишем полю "категория" ещё один класс для выпадающих списков.
Для тех, кто использует django-ckeditor5:
С использованием данного редактора вне панели администратора есть забавная особенность.
Дело в том, что поле с редактором в модели обязательно к заполнению, но если оставить поле формы обязательным, то форма не будет работать. JavaScript редактора самостоятельно обрабатывает ввод, а исходное поле формы скрывается. В результате получается так, что данные в редакторе есть, а в поле формы при этом ничего не введено. В связи с этим браузер не отправляет форму на сервер, считая, что форма не заполнена.
Для решения этой проблемы достаточно в форме указать, что она необязательна к заполнению, при этом в модели убирать обязательность не нужно. Если будет отправлена форма с пустым полем, то страница просто обновится и укажет на ошибку.
В __init__
указываем класс редактора и то, что поле не обязательно.
И прописываем стандартный внутренний класс Meta
с указанием на модель и перечислением полей.
Код формы:
from blog.models import PostModel
class AddPostByAuthorForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs.update({'class': 'form-control', 'autofocus': ''})
self.fields['short_body'].widget.attrs.update({'class': 'django_ckeditor_5'})
self.fields['full_body'].widget.attrs.update({'class': 'django_ckeditor_5'})
self.fields['category'].widget.attrs.update({'class': 'form-select'})
self.fields["short_body"].required = False
self.fields["full_body"].required = False
class Meta:
model = PostModel
fields = ('title', 'image', 'category', 'short_body', 'full_body', 'status', 'telegram_link',
'file', 'tags', 'telegram_body')
Представление страницы добавления поста.
Откроем файл views.py
.
Создадим класс AddPostByAuthorView
, унаследованный от двух классов: UserPassesTestMixin
и CreateView
.UserPassesTestMixin
- это класс в Django, предоставляющий удобный способ ограничения доступа к представлениям на основе пользовательских тестов. Он позволяет определить метод test_func
, который выполняет проверку и возвращает True
, если пользователь должен иметь доступ, или False
, если доступ следует отклонить. Если пользователь не проходит тест, то он перенаправляется на страницу, указанную в login_url
.
В классе пропишем три знакомых нам поля: template_name
, form_class
и model
.
Также три метода:
test_func
- в этом методе мы проверяем, что пользователь состоит в группе "Автор". Если пользователь в ней не состоит, то страница добавления поста не откроется.get_success_url
- указываем на какую страницу перенаправить пользователя после добавления поста.form_valid
- метод, проверяющий валидность формы. В нашем случае мы в ней заполняем два отсутствующих в форме поля:author
иslug
.
Код представления:
from django.contrib.auth.mixins import UserPassesTestMixin
from django.views.generic import CreateView
from pytils.translit import slugify
from blog.models import PostModel
from user_app import forms
class AddPostByAuthorView(UserPassesTestMixin, CreateView):
template_name = 'user_app/add_post.html'
form_class = forms.AddPostByAuthorForm
model = PostModel
def test_func(self):
return self.request.user.groups.filter(name='Автор').exists()
def get_success_url(self):
return reverse('user_app:user_profile', kwargs={'username': self.request.user.username})
def form_valid(self, form):
form.instance.slug = slugify(form.instance.title)
form.instance.author = self.request.user
return super().form_valid(form)
URL-паттерн страницы добавления поста.
Откроем файл urls.py
и в список urlpatterns
добавим следующую строку:
path('post/add_post/', views.AddPostByAuthorView.as_view(), name='add_post'),
Кнопка перехода на страницу добавления поста.
Я решил расположить кнопку в меню пользователя в шапке сайта.
Откроем файл header.html
и в блоке авторизованного пользователя добавим проверку на наличие в группе "Автор" и саму кнопку, если он там есть:
{% if "Автор" in user.groups.all.0.name %}
<li>
<a class="dropdown-item dd-item-color" href="{% url 'user_app:add_post' %}">Добавить
пост</a>
</li>
{% endif %}
Шаблон страницы добавления поста.
В директории с шаблонами приложения user_app
создадим файл add_post.html
.
В целом это обычная форма, за исключением одного момента.
Если вы используете django-ckeditor5
, то помимо стандартных csrf_token
и form.as_p
, необходимо добавить form.media
. Без этого редактор не будет отображаться.
Код шаблона:
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container mt-3 d-flex justify-content-center">
<div class="col-lg-8 col-sm-12">
<h2>Добавление поста</h2>
<form method="post" enctype="multipart/form-data" action="{% url 'user_app:add_post' %}">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button type="submit" class="btn btn-success mt-3">Сохранить</button>
</form>
</div>
</div>
{% endblock %}
Готово. Теперь авторы могут добавлять посты.
В следующем посте сделаем формы добавления категории и файлов.
Все статьи