Cat

Django 36. Добавление постов пользователем

В этом посте мы добавим группу пользователей "Автор". Реализуем форму добавления постов на стороне сайта, а также я расскажу о нюансах использования визуального редактора CKeditor5.

Все статьи

Icon Link

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

Icon Link

Реклама

Icon Link
Сайт на Django proDream 13 Ноябрь 2023 Просмотров: 1322

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

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

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

 

Библиотека 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 %}

 

Готово. Теперь авторы могут добавлять посты.
В следующем посте сделаем формы добавления категории и файлов.

 

Автор

    Нет комментариев

    Реклама