Запуск на ПК.
Для запуска на своём пк, достаточно выполнить несколько действий.
1. Склонировать проект с Github:
2. Перейти в папку проекта и запустить установку зависимостей:
3. Запустить скрипт:
4. Открыть браузер и перейти по адресу
Вот и всё. Можно пользоваться.
Запуск в Docker-контейнере.
Тут всё ещё проще.
1. Выполнить команду запуска контейнера:
2. Открыть браузер и перейти по адресу
Минимум действий.
Я запускал у себя на сервере в контейнере. Работает отлично, результаты выдаёт относительно корректные, но более подробные что-ли, нежели боты в ТГ.
Для запуска на своём пк, достаточно выполнить несколько действий.
1. Склонировать проект с Github:
git clone https://github.com/ramonvc/freegpt-webui.git
2. Перейти в папку проекта и запустить установку зависимостей:
cd freegpt-webui
pip install -r requirements.txt
3. Запустить скрипт:
python run.py
4. Открыть браузер и перейти по адресу
https://127.0.0.1:1338.Вот и всё. Можно пользоваться.
Запуск в Docker-контейнере.
Тут всё ещё проще.
1. Выполнить команду запуска контейнера:
docker run -p 1338:1338 -d ramonvc/freegpt-webui
2. Открыть браузер и перейти по адресу
https://127.0.0.1:1338.Минимум действий.
Я запускал у себя на сервере в контейнере. Работает отлично, результаты выдаёт относительно корректные, но более подробные что-ли, нежели боты в ТГ.
👍2🔥1
По поводу GPT у людей крайне неоднозначные мнения. И в связи с предыдущим постом, возник вопрос.
Как вы относитесь к GPT? Да и не только к GPT, но и другим подобным нейронкам.
Как вы относитесь к GPT? Да и не только к GPT, но и другим подобным нейронкам.
Anonymous Poll
33%
Нравится. Использую постоянно.
37%
Хорошая штука, но пользуюсь редко.
22%
Слышал, но не использую.
4%
Скептически, лучше головой думать.
0%
Категорически против! Точка!
4%
Свой вариант расскажу в комментариях.
AIOgram3 9. Команда start
API для регистрации пользователя написано, теперь нужно сделать команду
Без лишних слов. Откроем файл
Поскольку мы не получаем от API ничего, кроме статус-кода, создавать переменную, как в функции
В функции выше, мы отправляли
Первым параметром, как и ранее будет URL-адрес нашего API, можно взять его из предыдущей функции и изменить f-строку на URL для регистрации
API для регистрации пользователя написано, теперь нужно сделать команду
/start. Эта команда выполняется при первой инициализации бота пользователем. Без лишних слов. Откроем файл
api_actions.py в пакете utils и напишем функцию register_user для отправки данных по API. В качестве аргументов, она будет принимать следующие данные: chat_id, first_name, last_name, username. Поскольку мы не получаем от API ничего, кроме статус-кода, создавать переменную, как в функции
get_path, нет смысла. Сразу обращаемся к библиотеке requests.В функции выше, мы отправляли
GET запрос обращаясь к методу get из библиотеки requests. Сейчас нам необходимо отправить POST запрос, следовательно использовать будем метод post. Первым параметром, как и ранее будет URL-адрес нашего API, можно взять его из предыдущей функции и изменить f-строку на URL для регистрации
f"create-user/".Вторым параметром будет ключевой параметр
Обработчик написан, перейдём к созданию команды. В пакете
В файле напишем асинхронную функцию
В теле функции сразу вызываем нашу функцию
После вызова функции отправляем пользователю приветственное сообщение, предварительно создав функцию
Запустим Django и перейдём в панель администратора и откроем страницу модели
Теперь в отдельном окне запустим бота и выполним команду
Если, всё прошло удачно, то обновив страницу в панели администратора, увидите свой профиль.
Файлы к посту, можно получить в боте по коду: 260142
data, в котором создаём словарь с данными, где ключ - строка с названием переменной, а значение сама переменная.def register_user(chat_id, first_name, last_name, username):Стоит учесть, что поля
requests.post(API_URL + f"create-user/",
data={
'chat_id': chat_id,
'first_name': first_name,
'last_name': last_name if last_name else '',
'username': username if username else '',
})
last_name и username могут быть пустыми, по этому при помощи тернарного оператора, мы присваиваем значение переменной или пустую строку.Обработчик написан, перейдём к созданию команды. В пакете
handlers создадим файл simple.py. В этом файле мы будем писать простые команды, не требующие логики, такие как /start, /help, /about.В файле напишем асинхронную функцию
start_command, принимающую аргумент message.В теле функции сразу вызываем нашу функцию
register_user из файла api_actions.py, передавая в неё необходимые данные из объекта message. chat_id мы получаем обратившись к полю id метода chat - message.chat.id. Остальные переменные получаем из одноимённых полей метода from_user, например, message.from_user.first_name.После вызова функции отправляем пользователю приветственное сообщение, предварительно создав функцию
start_message с текстом в файле views.py.from aiogram.types import MessageОткроем файл
from botlogic import views
from botlogic.utils.api_actions import register_user
async def start_command(message: Message):
register_user(chat_id=message.chat.id,
first_name=message.from_user.first_name,
last_name=message.from_user.last_name,
username=message.from_user.username)
await message.answer(views.start_message())
main.py и зарегистрируем команду, добавив в функцию start после регистрации событий запуска/остановки, следующую строку: from botlogic.handlers import send_file, simpleТеперь протестируем работу.
dp.message.register(simple.start_command, Command(commands='start'))
Запустим Django и перейдём в панель администратора и откроем страницу модели
Пользователи бота. Должно быть пусто.Теперь в отдельном окне запустим бота и выполним команду
/start.Если, всё прошло удачно, то обновив страницу в панели администратора, увидите свой профиль.
Файлы к посту, можно получить в боте по коду: 260142
Приветствую.
Многие подписчики - студенты в GeekBrains на разных этапах учёбы, а также есть и те, кому просто интересно, полезны эти курсы или нет.
С самого начала обучения, я веду на Пикабу серию постов, о том, что мы проходим, чем я сам занимаюсь и как обстоят дела в целом.
Сегодня(на самом деле завтра) ровно год, как я начал учиться в GB.
Пост про 12й месяц обучения: https://pikabu.ru/story/obuchenie_dvenadtsatyiy_mesyats_10488283
Там же в профиле можно найти посты по другим месяцам.
Многие подписчики - студенты в GeekBrains на разных этапах учёбы, а также есть и те, кому просто интересно, полезны эти курсы или нет.
С самого начала обучения, я веду на Пикабу серию постов, о том, что мы проходим, чем я сам занимаюсь и как обстоят дела в целом.
Сегодня(на самом деле завтра) ровно год, как я начал учиться в GB.
Пост про 12й месяц обучения: https://pikabu.ru/story/obuchenie_dvenadtsatyiy_mesyats_10488283
Там же в профиле можно найти посты по другим месяцам.
🔥1
AIOgram3 10. Пара простых команд
Наш бот работает! Однако, в одном из прошлых постов, мы добавляли список команд в меню и помимо
Начнём с текста. Перейдём в файл
После того, как вы напишите свой текст, переходим в файл
Создадим две асинхронные функции:
В теле функций, выполним ответ пользователю на сообщение текстом из ранее созданных функций в файле
Наш бот работает! Однако, в одном из прошлых постов, мы добавляли список команд в меню и помимо
/get-file и /start, там ещё была команда /about. Давайте закрепим добавление команд и добавим команду /about и заодно /help.Начнём с текста. Перейдём в файл
views.py и создадим две функции: about_message и help_message. Они ничего не принимают, а просто возвращают соответствующую строку текста.После того, как вы напишите свой текст, переходим в файл
simple.py.Создадим две асинхронные функции:
about_command и help_command.В теле функций, выполним ответ пользователю на сообщение текстом из ранее созданных функций в файле
views.py.async def about_command(message: Message):
await message.answer(views.about_message())
async def help_command(message: Message):
await message.answer(views.help_message())
Для регистрации данных команд, перейдём в файл
Почти всё, перейдём в файл
Можно запустить бота и убедиться, что команды отображаются в меню. а бот корректно на них реагирует.
На этом с ботом пока всё. Возможно в будущем появится дополнительный функционал. Если у вас есть идеи, оставляйте их в комментариях!
Файлы к посту, можно получить в боте по коду: 209200
main.py и по аналогии с командой старт, сделаем две строки:dp.message.register(simple.about_command, Command(commands='about'))
dp.message.register(simple.help_command, Command(commands='help'))
Почти всё, перейдём в файл
commands.py и добавим новую команду help в меню. Для этого в списке commands продублируйте любую команду начинающуюся на BotCommand( и заканчивающуюся ),, изменив команду и описание. Список должен выглядеть следующим образом:commands = [
BotCommand(
command='start',
description='Начало работы'
),
BotCommand(
command='get_file',
description='получение файла с материалами'
),
BotCommand(
command='help',
description='Помощь по доступным командам'
),
BotCommand(
command='about',
description='Информация о боте'
),
]
Можно запустить бота и убедиться, что команды отображаются в меню. а бот корректно на них реагирует.
На этом с ботом пока всё. Возможно в будущем появится дополнительный функционал. Если у вас есть идеи, оставляйте их в комментариях!
Файлы к посту, можно получить в боте по коду: 209200
🔥2
Приветствую.
С ботом мы пока закончили, его необходимо разместить на сервере. Но тут есть два момента: Запускать на сервере данного бота бесполезно. Но инструкция по запуску, универсальна. Следует ли сейчас делать пост по запуску бота на сервере?
С ботом мы пока закончили, его необходимо разместить на сервере. Но тут есть два момента: Запускать на сервере данного бота бесполезно. Но инструкция по запуску, универсальна. Следует ли сейчас делать пост по запуску бота на сервере?
Anonymous Poll
40%
Делать пост
20%
Подождать сайт
40%
Сделать посты и по боту и сайту и общий
Django 16. Модель категорий
С ботом пока всё, приступим к разработке самого сайта.
В следующих постах сосредоточимся на следующем функционале:
- Разделы категорий
- Посты
- Поиск по сайту
Стоит отметить, что у меня достаточно поверхностные знания и навыки в вёрстке, по этому примеры шаблонов будут максимально простыми.
И начнём с категорий.
При создании модели категорий, мы будем использовать не встроенный в Django класс модели, а библиотеку
MPTT - это метод хранения и обработки иерархических данных в базе данных. Библиотека
Установим библиотеку
И пропишем в файле
С ботом пока всё, приступим к разработке самого сайта.
В следующих постах сосредоточимся на следующем функционале:
- Разделы категорий
- Посты
- Поиск по сайту
Стоит отметить, что у меня достаточно поверхностные знания и навыки в вёрстке, по этому примеры шаблонов будут максимально простыми.
И начнём с категорий.
При создании модели категорий, мы будем использовать не встроенный в Django класс модели, а библиотеку
django-mptt.MPTT - это метод хранения и обработки иерархических данных в базе данных. Библиотека
django-mptt позволит создавать и работать с иерархиями. Проще говоря, мы сможем сделать древовидное представление категорий.Установим библиотеку
pip install django-mptt и добавим её в requirements.txt.И пропишем в файле
settings.py, добавив mptt в список INSTALLED APPS.Откроем файл
Необходимо создать поля:
- Заголовок - строковое поле с названием категории
- Слаг/Slug - поле, формирующее из строки заголовка - slug-строку. Slug формируется только из ASCII символов, цифр и дефисов.
- Родитель - внешний ключ на родительскую категорию. Поскольку используется
- Описание - строковое поле, содержащее описание категории
Так же класс
Класс
Метод
И последним будет dunder-метод
Про поле
Аргумент
Аргументы
Аргумент
Аргумент
В поле
В классе
Класс
Появился новый метод
В следующем посте, займёмся шаблонами, зарегистрируем и протестируем модель позже.
Файлы к посту, можно получить в боте по коду: 157101
models.py и создадим класс CategoryModel наследующий MPTTModel.Необходимо создать поля:
- Заголовок - строковое поле с названием категории
- Слаг/Slug - поле, формирующее из строки заголовка - slug-строку. Slug формируется только из ASCII символов, цифр и дефисов.
- Родитель - внешний ключ на родительскую категорию. Поскольку используется
MPTTModel, то вместо стандартного ForeignKey используется TreeForeignKey.- Описание - строковое поле, содержащее описание категории
Так же класс
Meta, содержащий название модели и определяющий уникальную пару полей.Класс
MPTTMeta с сортировкой по вложенностям.Метод
get_absolute_url, возвращающий URL-адрес для объекта модели.И последним будет dunder-метод
__str__, возвращающим заголовок.from django.urls import reverse
from mptt.managers import TreeManager
from mptt.models import MPTTModel, TreeForeignKey
class CategoryModel(MPTTModel):
title = models.CharField(max_length=100,
verbose_name="Заголовок")
slug = models.SlugField(verbose_name="Альт. заголовок")
parent = TreeForeignKey('self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='children',
db_index=True,
verbose_name='Родительская категория')
description = models.CharField(max_length=350,
verbose_name="Описание",
blank=True)
objects = TreeManager()
class MPTTMeta:
order_insertion_by = ['title']
class Meta:
unique_together = [['parent', 'slug']]
verbose_name = 'Категория поста'
verbose_name_plural = 'Категории постов'
def get_absolute_url(self):
return reverse('blog:category_page', args=[int(self.pk), str(self.slug)])
def __str__(self):
return self.title
Про поле
parent. В поле создаётся объект класса TreeForeignKey из django-mptt, позволяющий делать древовидные категории. Аргумент self указывает, что внешний ключ ссылается на ту же модель, в которой он определен, то есть на CategoryModel.Аргумент
on_delete=models.CASCADE задает поведение при удалении связанного объекта. В данном случае, если родительская категория удалена, то все дочерние категории также будут удалены.Аргументы
null=True и blank=True позволяют полю parent быть необязательным и не требуют обязательного ввода значения при создании объекта.Аргумент
related_name='children' определяет имя обратной связи между родительской и дочерней категорией. То есть, у каждого объекта модели CategoryModel будет доступ к своим дочерним категориям через атрибут children.Аргумент
db_index=True создает индекс в базе данных, что позволяет ускорить поиск и сортировку по этому полю.В поле
objects будем использовать не обычного Django-менеджера, а специального для работы с MPTTModel.В классе
Meta, помимо привычных полей, появилось новое unique_together. Данное поле определяет какая пара полей модели должны быть уникальными.Класс
MPTTMeta, делает то-же, что и Meta, только для объектов модели MPTTModeL. Поле order_insertion_by определяет порядок вставки новых элементов в дерево. В нашем случае, элементы будут вставляться в порядке возрастания заголовка.Появился новый метод
get_absolute_url. Данный метод возвращает URL-адрес до страницы объекта. В следующем посте, займёмся шаблонами, зарегистрируем и протестируем модель позже.
Файлы к посту, можно получить в боте по коду: 157101
❤1👍1
Django 17. Разделение шаблонов
Шаблонизатор Jinja, используемый в Django, позволяет гибко управлять макетами, разбивая их на блоки, а так же, добавляя различные фильтры и конструкции, например, цикл
Макеты принято разбивать не на шаблоны страниц, а на отдельные модули.
Например, у нас есть главная страница, на которой есть: шапка, футер, блок со списком категорий, блок с последними постами, а так же блок популярных постов. Примерная структура:
Файл основного шаблона, содержащий подключения статических файлов, мета-теги, шапка и футер -
Файл шаблона главной страницы, в котором будет код, форматирующий блоки, так как нам надо. -
Файл блока списка категорий -
Файл блока последних постов -
Файл блока популярных постов -
Такая структура позволит избавится от огромных html файлов, выделив модули в отдельные файлы.
Шаблонизатор Jinja, используемый в Django, позволяет гибко управлять макетами, разбивая их на блоки, а так же, добавляя различные фильтры и конструкции, например, цикл
for или условие if. Макеты принято разбивать не на шаблоны страниц, а на отдельные модули.
Например, у нас есть главная страница, на которой есть: шапка, футер, блок со списком категорий, блок с последними постами, а так же блок популярных постов. Примерная структура:
Файл основного шаблона, содержащий подключения статических файлов, мета-теги, шапка и футер -
base.html.Файл шаблона главной страницы, в котором будет код, форматирующий блоки, так как нам надо. -
index.html.Файл блока списка категорий -
index_page/category_list.htmlФайл блока последних постов -
index_page/latest_posts.htmlФайл блока популярных постов -
index_page/popular_posts.htmlТакая структура позволит избавится от огромных html файлов, выделив модули в отдельные файлы.
Для начала изменим структуру нашего шаблона, который мы делали в одном из первых постов.
В директории
Сделав несколько переносов строки после
В директории
В файле так же создадим начало и конец блока, однако назовём его не
В файле пропишем наследование от
Зарегистрируем и протестируем.
Файлы к посту, можно получить в боте по коду: 179632
В директории
templates/blog, создадим файл index.html. Внутри пропишем наследование от базового шаблона, а так же тэги начала и конец блока с контентом:{% extends "blog/base.html" %}
{% block title %}Главная{% endblock %}
{% block content %}
{% endblock %}
Откроем файл base.html и из блока body вырежем блок section и поместим его в файле index.html между тэгами block content и endblock. Сделав несколько переносов строки после
section и до тега endblock добавляем подключение файла со списком категорий: {% block categories_list %}
{% include 'blog/index_page/category_list.html' %}
{% endblock %}
А на место где был блок section, в файле base.html вставим тэги:{% block content %}
{% endblock %}
Теперь при обращении к файлу index.html, будет подгружаться всё содержимое файла base.html.В директории
templates/blog, создадим новую директорию index_page. Должна получится следующая иерархия templates/blog/index_page. В ней создадим файл category_list.html.В файле так же создадим начало и конец блока, однако назовём его не
content, а categories_list и добавим код вывода категорий:{% block categories_list %}
{% load mptt_tags %}
<ul class="root">
{% recursetree categories_list %}
<li>
<a href="{{ node.get_absolute_url }}">{{ node.title }}</a>
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
{% endblock %}
Теперь необходимо создать файл для страницы категории. В директории templates/blog создадим файл category_page.html.В файле пропишем наследование от
base.html, пропишем теги блока контента и выведем название и описание категории:{% extends "blog/base.html" %}
{% block title %}{{ category.title }}{% endblock %}
{% block content %}
<h1>{{ category.title }}</h1>
<p>{{ category.description }}</p>
{% endblock %}
В следующем посте займёмся представлениями. Доработаем представление для главной страницы и напишем новое для страницы категории.Зарегистрируем и протестируем.
Файлы к посту, можно получить в боте по коду: 179632
👍1
Django 18. Представление для главной и категорий
Почти закончили с моделью категорий.
Осталось изменить представление главной страницы для вывода списка категорий, а так же добавить представление для страницы категории.
Откроем файл
В данный момент наше представление
В функции
Чуть ниже создадим переменную
Почти закончили с моделью категорий.
Осталось изменить представление главной страницы для вывода списка категорий, а так же добавить представление для страницы категории.
Откроем файл
views.py.В данный момент наше представление
index просто вывод заглушки. Оно ничего не передаёт в шаблон. Давайте это изменим.В функции
index, сделаем несколько отступов перед возвратом рендера. Там напишем переменную categories_list, в которой будем обращаться к нашей модели CategoryModel и получать все объекты через менеджера:categories_list = models.CategoryModel.objects.all()
Чуть ниже создадим переменную
context, это словарь, в котором ключом является имя переменной, к которой мы сможем обращаться внутри шаблона, а значением будут передаваемые данные. context = {
'categories_list': categories_list,
}Поскольку у нас теперь не
Напишем новую функцию
В шаблон небходимо передать информацию о текущей категории, для этого, создаём переменную
По аналогии создаём контекст и возврат рендера:
Готово. Теперь добавим URL-паттерн для страницы категорий. Откроем файл
Первым параметром мы формируем паттерн, состоящий из слова
Осталось зарегистрировать модель в панель адмниистратора. Откроем
Как можно заметить, мы наследуем наш класс не от
В кортеже
-
-
В переменной
Применим миграции:
Запустим Django и перейдём в панель администратора.
Там должна появиться наша модель. Сделайте несколько тестовых категорий разной вложенности, затем посмотрите как оно будет выглядеть на сайте.
Файлы к посту, можно получить в боте по коду: 234064
base.html выполняет функцию главной страницы, а index.html, ниже в строке с возвратом рендера изменим название файла и пропишем третьим параметром передачу в него контекста.return render(request,
'blog/index.html',
context)
Напишем новую функцию
category_page, принимающую в себя request, pk и slug.В шаблон небходимо передать информацию о текущей категории, для этого, создаём переменную
category и как и в предыдущей функции, получаем из модели данные. Только нам необходимы не все объекты, а конкретный.category = models.CategoryModel.objects.get(pk=pk)
По аналогии создаём контекст и возврат рендера:
context = {
'category': category,
}
return render(request,
'blog/category_page.html',
context)Готово. Теперь добавим URL-паттерн для страницы категорий. Откроем файл
urls.py в директории приложения и в список urlpatterns сайта, добавим следующую строку:path('category/<int:pk>-<str:slug>/', views.category_page, name='category_page'),Первым параметром мы формируем паттерн, состоящий из слова
category, pk категории и его slug-поля.Осталось зарегистрировать модель в панель адмниистратора. Откроем
admin.py и зарегистрируем:from mptt.admin import DraggableMPTTAdmin
@admin.register(models.CategoryModel)
class CategoryAdmin(DraggableMPTTAdmin):
list_display = ('tree_actions', 'indented_title', 'parent',)
list_display_links = ('indented_title',)
prepopulated_fields = {'slug': ('title',)}
search_fields = ['title', ]
Как можно заметить, мы наследуем наш класс не от
ModelAdmin, а от DraggableMPTTAdmin, данный класс позволяет организовать удобное отображение дерева категорий. В кортеже
list_display появились два не указанных в модели поля:-
tree_actions - добавляет в интерфейс функции взаимодействия с объектами.-
indented_title - поле заголовка с отступом.В переменной
prepopulated_fields мы прописываем, что поле slug будет заполняться автоматически на основе данных из поля title.Применим миграции:
python manage.py makemigrations
python manage.py migrate
Запустим Django и перейдём в панель администратора.
Там должна появиться наша модель. Сделайте несколько тестовых категорий разной вложенности, затем посмотрите как оно будет выглядеть на сайте.
Файлы к посту, можно получить в боте по коду: 234064
👍1
Django 19. Визуальный редактор CKEditor5
В прошлых постах сделали модель категорий. По хорошему теперь надо создать модель постов, но что бы не править модель в будущем, подготовим всё заранее.
Что бы посты выглядели прилично, с форматированием и рюшечками, установим визуальный редактор. Ранее, я использовал
Установим библиотеку
Не уходя из файла
В прошлых постах сделали модель категорий. По хорошему теперь надо создать модель постов, но что бы не править модель в будущем, подготовим всё заранее.
Что бы посты выглядели прилично, с форматированием и рюшечками, установим визуальный редактор. Ранее, я использовал
CKEditor, но в этот раз, решил опробовать CKEditor5. Установим библиотеку
pip install django-ckeditor-5. Вы уже должны были привыкнуть, что далее необходимо сразу добавить установленную библиотеку django-ckeditor-5==0.2.8 в requirements.txt. Также добавить django_ckeditor_5 в INSTALLED_APPS.Не уходя из файла
settings.py, в самый конец добавим конфигурацию:Код конфигурации ищите в файле settings.py в архиве с материалами к посту.
Переменная
Если вы используете тёмную тему панели администратора, то в директории
По умолчанию, редактор сохраняет изображения в корне директории
Создадим обработчик. Для этого перейдём в директорию приложения и создадим файл
В файле пропишем следующий код:
Настройки почти окончены, осталось прописать URL-паттерн. Перейдём в
Тем, кто читает данный пост, только, что бы узнать как установить редактор:
Для того, что бы форматированный в редакторе текст отображался на страницах сайта корректно, в шаблоне в тег вывода переменной с текстом, например,
Должно быть вот так:
В следующем посте начнём писать модель поста, будет много текста.
Файлы к посту, можно получить в боте по коду: 883614
CKEDITOR_5_CUSTOM_CSS задаёт пользовательские стили.Если вы используете тёмную тему панели администратора, то в директории
static необходимо создать директорию django_ckeditor_5 и в ней создать файл admin_dark_mode_fix.css со следующим содержимым:.ck.ck-editor {
color: black !important;
}По умолчанию, редактор сохраняет изображения в корне директории
media, что безусловно не удобно. Для того, что бы реализовать сохранение изображений в директориях post/%Y/%m/%d, служит параметр CKEDITOR_5_FILE_STORAGE. В нём определяется обработчик для сохранения файлов. Если у вас названия проекта совпадают, с моими, менять ничего не надо, если же не совпадают, то измените на соответствующие.Создадим обработчик. Для этого перейдём в директорию приложения и создадим файл
storage.py.В файле пропишем следующий код:
import os
from datetime import datetime
from urllib.parse import urljoin
from django.conf import settings
from django.core.files.storage import FileSystemStorage
class CustomStorage(FileSystemStorage):
"""Пользовательское хранилище для изображений."""
date = datetime.now().strftime('%Y/%m/%d')
location = os.path.join(settings.MEDIA_ROOT, f"post/{date}/")
base_url = urljoin(settings.MEDIA_URL, f"post/{date}/")
Настройки почти окончены, осталось прописать URL-паттерн. Перейдём в
urls.py в директории проекта и добавим в конец списка urlpatterns следующую строку:path("ckeditor5/", include('django_ckeditor_5.urls'), name="ck_editor_5_upload_file"),Тем, кто читает данный пост, только, что бы узнать как установить редактор:
Для того, что бы форматированный в редакторе текст отображался на страницах сайта корректно, в шаблоне в тег вывода переменной с текстом, например,
{{ post.body }} необходимо добавить фильтр safe. Должно быть вот так:
{{ post.body | safe }}.В следующем посте начнём писать модель поста, будет много текста.
Файлы к посту, можно получить в боте по коду: 883614
👍1
Приветствую.
Сайт для канала ещё в процессе разработки, но уже сейчас можно посмотреть, что получается.
Сайт: https://pressanybutton.ru/
Я уже говорил, что верстальщик из меня посредственный, поэтому, я буду рад вашим комментариям с предложениями, критикой или просто обсуждению сайта.
Сайт для канала ещё в процессе разработки, но уже сейчас можно посмотреть, что получается.
Сайт: https://pressanybutton.ru/
Я уже говорил, что верстальщик из меня посредственный, поэтому, я буду рад вашим комментариям с предложениями, критикой или просто обсуждению сайта.
🔥3👍2🤩1
Django 20. Модель поста
Сегодня напишем модель поста. Текста будет много и кода тоже.
Откроем файл
Создадим вложенный класс
Далее начнём описывать поля модели. У нас их будет 13 штук:
-
-
-
-
-
-
-
Сегодня напишем модель поста. Текста будет много и кода тоже.
Откроем файл
models.py и создадим новый класс PostModel унаследованный от models.Model.Создадим вложенный класс
Status унаследованный от models.TextChoices, в котором создадим два поля для статуса поста: Черновик и Опубликован.Далее начнём описывать поля модели. У нас их будет 13 штук:
-
title - поле с заголовком поста. Тип CharField.-
slug - поле преобразованное из заголовка в безопасный набор символов. Тип SlugField.-
image - поле для изображения поста. Тип ImageField.-
author - поле со ссылкой на пользователя, написавшего пост. Тип ForeignKey.-
category - поле со ссылкой на категорию. Тип TreeForeignKey.-
short_body - поле с коротким описанием/содержанием поста. Тип CKEditor5Field.-
full_body - поле с основным текстом поста. Тип CKEditor5Field.-
-
-
-
-
-
Далее вложенный класс
-
-
-
Метод
Методы
Dunder-метод
Код:
При желании, поле description в модели категории, так же можно изменить на CKEditor5Field, добавив в него графический редактор
publish - поле с датой публикации поста. Тип DateTimeField.-
created - поле с датой создания поста. Тип DateTimeField.-
updated - поле с датой обновления поста. Тип DateTimeField.-
status - поле со статусом поста. Выбор статуса происходит из класса Status. Тип CharField.-
views - поле со счётчиком просмотров. Тип IntegerField. Стоит отметить, что это не уникальные просмотры, а буквально каждое обновление страницы с постом, возможно в будущем, поле доработаем.-
objects - поле с определением менеджера для модели. Тип Manager.Далее вложенный класс
Meta со следующими полями:-
ordering - определяем сортировку по дате публикации в от самого нового.-
indexes - определяем индексирование базы данных по полю публикации.-
verbose_name и verbose_name_plural - определяем имя и множественное имя модели.Метод
get_absolute_url, возвращает URL-адрес для объекта модели.Методы
get_next_post и get_previous_post возвращают следующий и предыдущий пост в данной категории основываясь на дате публикации.Dunder-метод
__str__ возвращает заголовок поста.Код:
from django_ckeditor_5.fields import CKEditor5Field
from django.contrib.auth.models import User
from django.utils import timezone
class PostModel(models.Model):
"""Модель поста"""
class Status(models.TextChoices):
"""Класс выбора статуса поста"""
DRAFT = 'ЧЕ', 'Черновик'
PUBLISHED = 'ОП', 'Опубликовано'
title = models.CharField(max_length=200,
verbose_name="Заголовок")
slug = models.SlugField(verbose_name="Альт. заголовок")
image = models.ImageField(upload_to='post/%Y/%m/%d',
default='default/not_found.png',
verbose_name='Изображение поста')
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='post',
verbose_name="Автор")
category = TreeForeignKey('CategoryModel',
on_delete=models.PROTECT,
related_name='post',
verbose_name='Категория')
short_body = CKEditor5Field(max_length=350,
verbose_name="Краткое описание",
blank=True)
full_body = CKEditor5Field(verbose_name='Содержимое поста')
publish = models.DateTimeField(default=timezone.now,
verbose_name="Опубликовано")
created = models.DateTimeField(auto_now_add=True,
verbose_name="Создано")
updated = models.DateTimeField(auto_now=True,
verbose_name="Обновлено")
status = models.CharField(max_length=2,
choices=Status.choices,
default=Status.DRAFT,
verbose_name="Статус")
views = models.IntegerField(default=0,
verbose_name="Количество просмотров")
objects = models.Manager()
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
verbose_name = 'Пост'
verbose_name_plural = 'Посты'
def get_absolute_url(self):
"""Метод получения URL-адреса объекта"""
return reverse('blog:post_page', args=[int(self.pk), str(self.slug)])
def get_next_post(self):
"""Метод получения следующего поста"""
try:
return self.get_next_by_publish(category=self.category)
except PostModel.DoesNotExist:
return None
def get_previous_post(self):
"""Метод получения предыдущего поста"""
try:
return self.get_previous_by_publish(category=self.category)
except PostModel.DoesNotExist:
return None
def __str__(self):
return self.title
При желании, поле description в модели категории, так же можно изменить на CKEditor5Field, добавив в него графический редактор
Применим миграции:
Файлы к посту, можно получить в боте по коду: 398438
python manage.py makemigrationsПо аналогии с моделью категории нам далее необходимо: Зарегистрировать модель в панели администратора, написать представление для страницы поста, добавить URL-паттерн и сделать шаблон страницы с постом. Этим займёмся в следующих постах.
python manage.py migrate
Файлы к посту, можно получить в боте по коду: 398438
Django 21. Регистрация модели поста
Модель создали, теперь необходимо выполнить ещё ряд действий.
Начнём с регистрации модели в панели администратора. Перейдём в файл
Далее создаём 7 полей:
-
-
-
-
Модель создали, теперь необходимо выполнить ещё ряд действий.
Начнём с регистрации модели в панели администратора. Перейдём в файл
admin.py и создадим класс PostAdmin унаследованный от admin.ModelAdmin. Так же не забудьте про декоратор над классом или строку с регистрацией класса в самом низу файла, в зависимости от того, каким способом вы регистрируете модель.Далее создаём 7 полей:
-
list_display - Список имен полей модели, которые должны быть отображены в списке объектов.-
list_filter - Список имен полей, по которым Django создаст фильтры в правой части страницы изменения списка.-
search_fields - Активирует поиск в правом верхнем углу страницы со списком объектов.-
prepopulated_fields - Словарь, определяющий поля, которые должны быть автоматически заполнены из значений других полей.