Django 14. Модель пользователя бота
Продолжим добавлять функционал боту и Django. Сегодня сделаем модель для пользователя ботом. Это позволит получать статистику по использованию бота прямо в панели администратора Django.
Перейдём в файл
И создадим несколько полей:
Продолжим добавлять функционал боту и Django. Сегодня сделаем модель для пользователя ботом. Это позволит получать статистику по использованию бота прямо в панели администратора Django.
Перейдём в файл
models.py в директории приложения и по аналогии с предыдущей моделью, создадим новый класс BotUserModel.И создадим несколько полей:
class BotUserModel(models.Model):Разберём, что тут новое:
chat_id = models.BigIntegerField(primary_key=True)
first_name = models.CharField(max_length=50,
verbose_name='Имя')
last_name = models.CharField(max_length=50,
blank=True,
null=True,
verbose_name='Фамилия')
username = models.CharField(max_length=50,
blank=True,
null=True)
created = models.DateTimeField(auto_now_add=True,
verbose_name='Зарегистрирован')
updated = models.DateTimeField(auto_now=True,
verbose_name='Последняя активность')
- В поле
chat_id, указали, что это поле является Первичным ключом. То есть, это поле уникально. И использовали поле типа BigIntegerField, поскольку значения Telegram-ID выходят за границы базового IntegerField.- В полях
last_name и username добавили два параметра. blank означает, что поле может быть пустым, а null означает, что оно может иметь значение NULL. Это обусловлено тем, что имя у пользователя Telegram обязательно к заполнению, а вот фамилия или имя пользователя - нет.- В поле
created мы присваиваем текущую, локальную дату(дату сервера). При последующем обновлении модели, это поле не будет изменяться, если конечно его не изменить намерено.- Поле
updated напротив, будет при каждом обновлении модели принимать значение текущего времени.Добавим базового менеджера, Мета-класс и dunder-метод
__str__:objects = models.Manager()В переменную objects мы поместили экземпляр класса
class Meta:
ordering = ['-updated']
verbose_name = 'Пользователь бота'
verbose_name_plural = 'Пользователи бота'
def __str__(self):
return self.first_name
Manager. Менеджеры, это удобный способ взаимодействия с объектами в базе данных. С помощью них получаем данные, фильтруем, создаём. В будущем мы переопределим своих менеджеров, но пока достаточно базового.Из нового в классе
Meta только пункт ordering определяющий порядок сортировки записей в базе данных. Для удобства сортировка будет по параметру updated. Обратите внимание на "-", он означает что сортировка будет в обратном порядке, то есть по убыванию, от самых новых к старым.Перейдём в файл
admin.py и зарегистрируем модель в панели администратора:@admin.register(models.BotUserModel)Обратит внимание! Если вы регистрировали модель не через декоратор, а через admin.site.register, то код находящийся выше, надо добавлять до строки с регистрацией!
class BotUserAdmin(admin.ModelAdmin):
list_display = ('chat_id', 'first_name', 'last_name', 'username', 'created', 'updated')
search_fields = ['chat_id', 'first_name', 'username', ]
Здесь я указал, что бы отображались все поля модели. Включил поиск по полям
chat_id, first_name и username.Теперь надо применить миграции:
python manage.py makemigrationsЗапустим Django
python manage.py migrate
python manage.py runserver и убедимся, что модель добавилась в панель администратора.Файлы к посту, можно получить в боте по коду: 347837
Пост на сайте.
Поддержать канал.
#django #python #модель #бот #aiogram
👍1
Django 15. Пишем API - Добавление пользователя
Теперь давайте напишем API, обращаясь к которому мы будем создавать или обновлять пользователя.
Откроем файл
В прошлый раз мы делали метод для
Далее создаём переменную
Теперь давайте напишем API, обращаясь к которому мы будем создавать или обновлять пользователя.
Откроем файл
api.py и создадим класс CreateBotUser и статический метод post.В прошлый раз мы делали метод для
GET запроса, в этот раз наш бот не получает, а передаёт данные по API, именно по этому нам нужен POST запрос.class CreateBotUser(APIView):
@staticmethod
def post(request):
Далее создаём переменную
usr_obj в которую мы, с помощью метода get_or_create получим объект пользователя, если пользователь с chat_id уже есть в базе, если же его нет, он будет создан и так же помещен в переменную:usr_obj: models.BotUserModel = models.BotUserModel.objects.get_or_create(
chat_id=request.data['chat_id'],
defaults={
'first_name': request.data['first_name'],
'last_name': request.data['last_name'],
'username': request.data['username'],
})[0]
В параметре
Затем, независимо от того, был пользователь только что создан или нет, мы обновляем значение поля
Файлы к посту, можно получить в боте по коду: 786103
defaults передаются значения полей, которые будут записаны, если пользователя нет.Затем, независимо от того, был пользователь только что создан или нет, мы обновляем значение поля
updated на актуальное время, вызвав сохранение объекта. И возвращаем пустой ответ со статус-кодом 200:usr_obj.save()Добавим URL-адрес для отправки запроса. Перейдём в файл
return Response(status=200)
urls.py и в список urlpatterns отведённый для URL-паттернов нашего API добавим строку:# Паттерны APIНа этом создание API закончено, теперь необходимо написать в боте отправку запроса при выполнении команды.
urlpatterns += [
path('bot/get-file/', api.GetFilePath.as_view()),
path('bot/create-user/', api.CreateBotUser.as_view()),
]
Файлы к посту, можно получить в боте по коду: 786103
👍1
Полезные инструменты - Бесплатный CHAT-GPT4 на вашем сервере
Приветствую.
Буквально вчера мне написал одногруппник и скинул видео. В этом видео рассказывалось о том, как запустить чат GPT у себя на пк. Само видео смотреть не стал, сразу ринулся изучать гитхаб проекта.
Страница проекта: https://github.com/ramonvc/freegpt-webui
В данном проекте собраны различные модели нейросетей. Можно выбрать как GPT-4, так и Sage или Claude.
Вся обработка происходит на сторонних серверах, мы выступаем в роли клиента.
Есть два способа использовать проект.
1. Запускать на локальном ПК.
2. Запускать в Docker-контейнере.
В обоих случаях запуск не вызывает трудностей.
Приветствую.
Буквально вчера мне написал одногруппник и скинул видео. В этом видео рассказывалось о том, как запустить чат GPT у себя на пк. Само видео смотреть не стал, сразу ринулся изучать гитхаб проекта.
Страница проекта: https://github.com/ramonvc/freegpt-webui
В данном проекте собраны различные модели нейросетей. Можно выбрать как GPT-4, так и Sage или Claude.
Вся обработка происходит на сторонних серверах, мы выступаем в роли клиента.
Есть два способа использовать проект.
1. Запускать на локальном ПК.
2. Запускать в Docker-контейнере.
В обоих случаях запуск не вызывает трудностей.
Запуск на ПК.
Для запуска на своём пк, достаточно выполнить несколько действий.
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