Код на салфетке – Telegram
Код на салфетке
2.39K subscribers
776 photos
21 videos
2 files
814 links
Канал для тех, кому интересно программирование на Python и не только.

Сайт: https://pressanybutton.ru/
Чат: https://news.1rj.ru/str/+Li2vbxfWo0Q4ZDk6
Заметки автора: @writeanynotes

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
Всем привет)

Стрима сегодня не будет потому, что я не придумал тему)

В чате кота появилось несколько идей и чтобы они не потерялись, прошу продублировать их в комментариях к этому посту.

В течении недели буду собирать идеи и будем выбирать, что будем делать в следующее воскресенье.
🔥2😁1
Вчера мы опубликовали задачу, которая отсылает нас ко второму посту Андрея "== != is". Судя по количеству верных ответов, а их всего 15% или 6 человек из 39-ти, без пояснений не обойтись.


Код задачи:
a = 200
b = 20
c = 300
d = 30

print(a is b * 10, c is d * 10)



Разберём задчу.
Создаём четыре меременные - a, b, c и d. В каждую переменную определяем число.

Затем, вызвав функцию print() выводим на экран два выражения:
1. a is b * 10 - Проверяем, что число в переменной a это число из переменной b умноженное на 10.
2. c is d * 10 - Проверяем, что число в переменной c это число из переменной d умноженное на 10.


Что пошло не так?
В результате после проведения математических операций, у нас будет следующие проверки:
- 200 это 200?
- 300 это 300?

49% участников ответили "Да!" и оказались не правы.

"Соль" заключается в способе хранения Python'ом чисел в оперативной памяти. Если говорить максимально просто, то числа от 0 до 255 хранятся в "зарезервированной" памяти, в случае с числами больше 255, каждый раз создаётся своя ячейка.

Проверить это можно следующим образом:
a = 200  
b = 20
c = 300
d = 30

print(f"{id(a)=}\n{id(b * 10)=}\n{id(c)=}\n{id(d * 10)=}")


В результате получим следующий вывод:
id(a)=140716981156872
id(b * 10)=140716981156872
id(c)=2349489175568
id(d * 10)=2349492150192


Как видим, в первых двух строках id совпадает, а вторых двух - нет.


Заключение.
Как видим, все не так просто в Python с хранением данных в памяти. Стоит помнить и понимать работу, дабы быть готовым к неожидонностям.
Настоятельно рекомендую прочитать статью Андрея, для закрепления - "== != is"
🔥13👍2
Весна – отличное время года. Весной приходит тепло, солнце греет сильнее, сходит снег и появляются первые цветы... Ещё весной рождаются хорошие люди. Одним из таких людей оказалась Кристина Большакова!

Не перечислить сколько всего Кристина делает для Канала и Некого проекта. Организует работу, помогает с делами, придумывает задачи, подкидывает идеи и, конечно же, лупит нас тапком, когда мы начинаем лениться.

В этот замечательный день хочу поздравить Кристину с днём рождения.
Желаю тебе оставаться и дальше такой продуктивной, активной и да не устанет лупящая рука твоя. Пусть твои дети как можно реже болеют и чаще приносят “пятерки” из школы. Пусть каждый день приносит радость и приятные эмоции. Спасибо, что помогаешь нам.


А сейчас передаю слово ГлавВреду Андрею Лебедеву:

Если абстрагироваться от того, что день рождения сегодня у неё и именно она должна принимать поздравления и подарки, то Кристина — сама по себе подарок для всех участников наших проектов. Она не только помогает всем задействованным людям придерживаться взятых на себя обязательств, но и вдохновляет, мотивирует и стоит у истоков всего, что мы делаем.

Наш канал и Некий проект — это инициативы, которые держатся на доброй воле тех, кто ими занимается. И если воля у нас у всех общая, то Кристина отвечает именно за доброту. Для каждого у Кристины найдётся тёплое слово. Любого она найдёт, чем ободрить и поддержать.

Я благодарен всем ребятам за идеи, знания и опыт, которыми мы делимся, работая над проектами. Но конкретно Кристине хочется сказать спасибо за атмосферу и за то, как мы все чувствуем себя. Спасибо тебе большое! Будь здорова, счастлива и любима!


И Артуру Мурзыеву:

Дорогая Кристина! Поздравляю тебя с Днём Рождения! Желаю тебе здоровья, радости, любви, успехов во всех делах. Чтобы всегда оставалась такой же бодрой и энергичной! С Днём Рождения!
🎉72🔥2
Создание резервных копий VPS на Яндекс Диск
Автор: Иван Ашихмин

Бэкапы – больная тема. Разработчики скажут "какие бэкапы? У меня есть git!" и будут правы. Частично. Git, безусловно, позволяет откатиться на прошлую, "рабочую", версию. Но что будет, если откажет накопитель с проектом, который был размещен локально? Или случатся проблемы с сервером, где, помимо файлов проекта, лежит ещё и БД?

Где бэкапы? Где резервные копии? Их нет... Давайте исправим это.

Почему я задумался о бэкапах? Всё просто. У меня на сервере сейчас много всего:

- Сайт https://pressanybutton.ru/
- Telegram-бот для канала и чата https://news.1rj.ru/str/press_any_button_bot
- Собственный git-сервер на базе Gitea.
🔥2
- Собственный почтовый сервер на базе Docker Mailserver.
- Собственная Wiki на базе WikiJS.
- И БД PostgreSQL для всего этого.


Потерять это будет крайне обидно.

Мой VPS приобретён у Timeweb. У них хорошие сервера и поддержка, но я не застрахован от внештатных ситуаций. Они, конечно, предоставляют услугу по созданию резервных копий, но она стоит 180 рублей в месяц при одном бэкапе в день/неделю/месяц. Если нужно хранить 7 копий на всю неделю, это 1260 рублей в месяц, что уже "кусается". Делать же всего одну копию вчерашнего дня или раз в неделю – не так уж эффективно.

С другой стороны, у меня есть подписка на "Яндекс 360", предоставляющая 1ТБ за 2290 рублей в год. Почему бы не воспользоваться этим хранилищем?

В итоге формируется следующая задача: необходимо организовать резервное копирование данных на сервере и отправку их на Яндекс Диск.

В качестве программы для создания резервных копий мы будем использовать Restic.Документация доступна по ссылке: https://restic.readthedocs.io/en/stable/

Яндекс Диск подключим, как удалённое хранилище при помощи rclone.Документация доступна по ссылке: https://rclone.org/

Конфигурация используемого VPS:
- CPU: 2 x 3.3ГГц
- RAM: 4 Гб
- NVMe: 30 Гб
- OS: Debian 12


Все действия производятся в терминале подключенном к VPS по SSH.



Установка и настройка rclone.
Начнём мы с подключения Яндекс Диска в качестве доступного в системе раздела.

Для установки rclone, выполним в терминале команду:


sudo -v ; curl https://rclone.org/install.sh | sudo bash

В результате должно быть сообщение как на скриншоте:

После установки нам необходимо установить подключение к Яндекс Диску, создав новое удалённое подключение в rclone.

Настройка выполняется в интерактивном режиме. Для начала настройки необходимо выполнить команду:


rclone config

Первое сообщение оповещает о том, что у нас нет файла настроек и будет создан новый. Далее предлагается три варианта действий:

- n - Новое подключение
- s - Установить пароль
- q - Выйти из настроек.


Нам необходим первый вариант. Нажимаем клавишу n и отправляем.

Следующим действием нас просят указать имя подключения. Вписываем.

Далее отобразится большой список поддерживаемых сервисов, в котором необходимо найти нужный нам Yandex Disk и ввести его номер или краткое название, указанное в скобках. В моём случае это номер 52 и имя (yandex).

Далее будет три вопроса о вводе client_id, client_secret и расширенные настройки. Первые два оставляем пустыми, а в третьем выбираем n.

Затем нас попросят выбрать, открыть браузер для авторизации на сайте или нет. Поскольку мы подключились по SSH к VPS, никакого браузера у нас нет, выбираем n.

И тут возникает сложность. Нам необходимо авторизоваться в Яндекс, а для этого необходимо запустить rclone на локальной машине, где есть возможность открыть браузер.Скачиваем бинарный файл для своей системы на сайте: https://rclone.org/downloads/Пользователи Linux могут воспользоваться командой описанной выше.Локальная машина у меня на Windows, поэтому все действия буду выполнять на ней.


Не разрываем соединение с VPS сервером! Все действия проводим во втором открытом окне терминала!


Скачиваем и распаковываем архив с программой: https://downloads.rclone.org/v1.66.0/rclone-v1.66.0-windows-amd64.zip

Открываем в этой директории терминал.

Копируем команду, указанную в сообщении на VPS, заменив в начале rclone на .\rclone.exe. Выполняем.

В браузере откроется страница с авторизацией в Яндекс. Вводим логин и пароль. Затем разрешаем доступ к Диску.
🔥4
После того, как увидели надпись Success!, возвращаемся в терминал и видим несколько строк с токеном. Копируем его и вставляем в терминал VPS.

Нас попросят подтвердить, что всё верно. Печатаем и отправляем y.

На этом добавление подключения закончено.

Не отходя от rclone, создадим директорию для хранения бэкапов на диске, выполнив команду:


rclone mkdir yandex_disk:vps_backup

Где yandex_disk - имя подключения, а vps_backup - имя директории.


Установка и настройка Restic.
После того, как мы подключили rclone, можно устанавливать Restic.

Для установки выполним команду:


apt-get install restic

Далее инициализируем созданное подключение, выполнив команду:


restic -r rclone:yandex_disk:vps_backup init

Нас сразу попросят ввести пароль от репозитория, так называются хранилища в Restic. Вводим.
Сохраните пароль! Без него не будет доступа к репозиторию!


Для создания бэкапа используем команду:


restic -r rclone:yandex_disk:vps_backup backup /root

Где /root - директория, которая будет сохранена в резервной копии.

Начнётся процесс создания резервной копии. В моём случае на 7 Гб данных из 38 тысяч файлов, заняло чуть меньше 9-ти минут. Дольше всего добавлялись файлы git-сервера. Следующие бэкапы будут производиться быстрее, поскольку тут система похожа с git - создаётся изначальный индекс репозитория, а затем добавляются или удаляются файлы как "коммиты", называемые "снимками".

Всё предельно просто.


Автоматический запуск создания резервной копии.
Автоматизировать создание бэкапов нам поможет cron, но сперва мы напишем простейший скрипт для вызова команды Restic.

Создадим новый файл backup_noscript.sh, вызвав команду:


touch backup_noscript.sh

Затем откроем его в nano и пропишем следующее содержимое:


#!/bin/bash

export RESTIC_PASSWORD="password"

restic -r rclone:yandex_disk:vps_backup backup /root

В первой строке прописываем так называемый "шебанг". Это строка начинающаяся с #! и указывающая путь к интерпретатору или программе, в которой следует выполнить описанный в файле код.В третьей строке мы передаём пароль от репозитория в переменные окружения.В пятой строке вызываем команду создания бэкапа.

Нажимаем CTRL+S для сохранения и CTRL+X ля выхода.

Далее файлу необходимо дать права на исполнение. Выполним команду:


chmod +x backup_noscript.sh

Затем запустим crontab для редактирования, выполнив команду:


crontab -e

И впишем туда следующую строку:


30 0 * * * /root/backup_noscript.sh

Стока выше определяет, что скрипт указанный по пути будет запускаться каждый день в 00:30.

Проверить работу и посмотреть список снимков можно командой:


restic -r rclone:yandex_disk:vps_backup snapshots


Восстановление резервной копии.
Резервную копию сделали, а как восстанавливать? Всё достаточно просто.

Для того, чтобы восстановить снимок, достаточно выполнить две команды.

Первая команда описана выше, сперва необходимо выбрать идентификатор снимка для восстановления:


restic -r rclone:yandex_disk:vps_backup snapshots

Вторая команда непосредственно восстанавливает снимок:


restic -r rclone:yandex_disk:vps_backup restore <ID> --target /root

Вместо <ID> вписываем идентификатор снимка.


Заключение.
Мы подключили к VPS Яндекс Диск и настроили автоматическое создание резервных копий. Тема была интересна, и я надеюсь, что бэкапы так и останутся невосстановленными.
🔥9👍1
Приветствую!

Каналу исполнилось 9 месяцев!

За это время:
- Вышло свыше 120 постов.
- На канал подписались 473 человек!
- На сайте примерно 80-100 ежедневных посещений.
- Стримы и другие активности.

Спасибо всем тем, кто читает наши посты. Тем, кто участвует в обсуждении. И тем, кто поддерживает нас.

Впереди много планов, которые по чуть-чуть да воплощаются.
🔥13❤‍🔥222🆒1
Отправка поста с Django в AIOgram - обновление
Автор: Иван Ашихмин

В посте "Django + AIOgram3 + Redis - Отправка поста с Django в AIOgram" я рассказывал как отправлять текст поста в AIOgram, обрабатывать и публиковать в Telegram-канале.
Это была первая версия обработчика, которая работала, но была не совсем удобна в использовании.

После нескольких месяцев использования прошлой системы, появилась необходимость "апгрейда" для более удобной публикации постов с сайта в канале.

Обновление основано на файлах из поста: "Django + AIOgram3 + Redis - Отправка поста с Django в AIOgram".


Продолжение в посте на Boosty (платный контент)

Пост на сайте
Поддержать проект

#Python #Django #Гайды #Telegram #AIOgram #Telegram_бот #AIOgram3 #бот #Boosty #автоматический_постинг
🔥3👍1
Добрый вечер! Пятница наступила!

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

Фильм: Путь домой

Год: 2010

1940 год, Сибирь. Самый страшный лагерь для политзаключенных. Небольшая группа осужденных смогла вырваться из этого страшного места. Теперь их ждёт долгий и трудный путь домой: выживание в пустыне, переход через горы, столкновение с дикими животными и встречи с незнакомыми людьми. Они идут домой из последних сил, надеясь на встречу со своими близкими.

https://www.sspoisk.ru/film/430638/

Приятного просмотра!
🔥4
Что выведет этот код? №16
🔥2🤓1
Вчера мы опубликовали задачу на знание основ работы словарей в Python. Задачу верно решило большее число ответивших, а именно 66%.

Код задачи:
dct = {
"10": "Желает",
"2": "Знать",
"1": "Охотник",
"22": "Где",
"3": "Сидит",
"0": "Каждый",
"30": "Фазан"
}

print(sorted(dct.values()))


Разбор задачи:
Задача состоит из двух шагов:
1. Создаём переменную dct, в которой прописываем словарь.
2. Выводим на печать отсортированный список значений словаря.

Что происходит в коде?
В переменной dct мы прописали словарь, в котором и ключи, и значения – строки.

Далее мы хотим его отсортировать, но не указываем по какому параметру, а только лишь передаём в "сортировщик" список (list) со значениями. Возможно, кого-то этот ход обманул: мы действительно просто сортируем список значений словаря, вне всякой зависимости от ключей, которые оказываются просто отброшенными.

В Python сортировка строк осуществляется побуквенно, т.е. строка символов преобразуется в список чисел, где каждый элемент – это число из unicode-таблицы символов. При этом строка из четырёх символов будет всегда считаться меньшей, чем строка из пяти, если четыре первые символа в обеих строках совпадают.
Например, "абвг" будет идти после "абв" или "Я" будет считаться меньше чем "а".

В нашем же примере слова просто отсортируются по алфавиту:

Где
Желает
Знать
Каждый
Охотник
Сидит
Фазан

Если же мы хотим получить "правильный" порядок, основанный на ключах, то можно воспользоваться сортировкой по ключу:
print([v for _, v in sorted(dct.items())])


В примере выше в функцию sorted() попадёт кортеж (ключ: значение), и сортировка будет по первому элементу – т.е. по ключу. Затем в цикле выводим значение на экран и получаем:
['Каждый', 'Охотник', 'Желает', 'Знать', 'Где', 'Сидит', 'Фазан']
🔥6
Django 41. Комментарии к постам
Автор: Иван Ашихмин

В нашем проекте не хватает одного важного элемента – блока комментариев на странице поста. Давайте исправим это.

Что мы сделаем:

- Добавим на страницу поста отображение комментариев.
- Добавим возможность авторизованным пользователям оставлять комментарии.
- Также у автора комментария или администратора должна быть возможность удалить или отредактировать комментарий.



Модель комментария.
Для хранения комментариев нам нужна модель.

Откроем файл models.py в директории приложения blog.

Создадим класс CommentModel, унаследованный от models.Model, и пропишем четыре поля:

- user – Внешний ключ на модель пользователя.
- post – Внешний ключ на модель поста. Для доступа к модели комментария из объекта модели поста указываем аргумент related_name="comments".
🔥1
- comment – Текстовое поле для комментария.
- created_at – Поле с датой написания комментария.


Также пропишем внутренний класс Meta с названием модели и dunder-метод __str__ с текстовым представлением объекта модели.


Код модели:

class CommentModel(models.Model):  
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="Пользователь"
)
post = models.ForeignKey(
PostModel,
on_delete=models.CASCADE,
verbose_name="Пост",
related_name="comments",
)
comment = models.TextField(verbose_name="Комментарий")
created_at = models.DateTimeField(auto_now_add=True)

class Meta:
verbose_name = "Комментарий"
verbose_name_plural = "Комментарии"

def __str__(self):
return f"Комментарий от {self.user} к посту {self.post}"


Регистрация в панели администратора.
Откроем файл admin.py.

Создадим класс CommentAdmin, унаследованный от admin.ModelAdmin. Обернём его в декоратор @admin.register(), передав в качестве аргумента модель комментария.

Внутри класса поля можно прописать по желанию, например:

- list_display - отображаемые столбцы.
- list_filter - выбор по каким полям проводить фильтрацию.


Дополнительно добавим столбец с названием поста при клике на которую будет открываться страница поста.

Для этого создадим метод post_link, в аргументах он принимает self и объект модели obj.
Внутри метода, используя функцию mark_safe, возвращаем строку со ссылкой.

Затем ниже вызываем метод allow_tags и устанавливаем его в True. Это позволит выводить HTML на странице панели администратора.

Не забываем прописать новое поле в list_display.


Код класса:

@admin.register(models.CommentModel)  
class CommentAdmin(admin.ModelAdmin):
list_display = ("user", "post_link", "created_at", "comment")
list_filter = ("user", "post")

def post_link(self, obj):
return mark_safe(
f'<a href="{obj.post.get_absolute_url()}">{obj.post.noscript}</a>'
)

post_link.allow_tags = True


Форма добавления комментария.
Для того чтобы можно было добавлять новый комментарий, необходима форма модели.

Откроем файл forms.py и создадим класс CommentForm, унаследованный от forms.ModelForm.

Форма будет весьма классическая:

- Определяем поле comment.
- Прописываем класс Meta, указав модель и всего одно поле - comment.



Код формы:

class CommentForm(forms.ModelForm):  
comment = forms.CharField(
widget=forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Введите текст комментария",
"rows": 5
}
),
)

class Meta:
model = CommentModel
fields = ("comment",)


Представления.
Теперь займёмся представлениями. Нам для комментариев нужно три представления:

- Добавление комментария.
- Редактирование.
- Удаление.


Также необходимо изменить представление страницы поста для передачи в него формы комментария.


Представление страницы поста.
Откроем файл views.py. Найдём класс PostPageView и добавим метод get_context_data.
Он тоже весьма стандартный. Внутри метода в контекст добавим новый ключ comment_form, в который определим объект формы CommentForm.


Код метода:
🔥1
def get_context_data(self, **kwargs):  
context = super().get_context_data(**kwargs)
context["comment_form"] = CommentForm()
return context


Базовое представление.
Нам понадобится три представления, и по сути они идентичны. Различия только в наследуемых классах, поэтому, чтобы избежать дублирования кода, создадим базовый класс BaseCommentView.

В классе пропишем поле model, в котором определим класс модели комментария.

И переопределим метод get_success_url, принимающий только self.
В нём мы вернём путь до страницы поста.


Код класса:

class BaseCommentView:  
model = CommentModel

def get_success_url(self):
post = models.PostModel.objects.get(pk=self.object.post.pk)
return reverse(
"blog:post_page",
kwargs={"category_slug": post.category.slug, "slug": post.slug},
)


Представление добавления комментария.
Создадим класс AddCommentView, унаследованный от BaseCommentView и CreateView, который будет отвечать за добавление комментария.

В нём мы добавим поле form_class, определив в нём класс формы.

И переопределим метод form_valid, принимающий self и объект формы form.
Поскольку в модель класса требуется передавать пользователя и связанный с комментарием пост, а в форме мы не можем этого сделать, определим их тут.
Внутри метода определяем поля user и post, затем вызываем super-метод для сохранения объекта.


Код представления:

class AddCommentView(BaseCommentView, CreateView):  
form_class = CommentForm

def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post = models.PostModel.objects.get(pk=self.kwargs.get("pk"))
return super().form_valid(form)


Представления редактирования и удаления комментария.
Создадим два класса:

- EditCommentView, унаследованный от BaseCommentView и UpdateView.
- DeleteCommentView, унаследованный от BaseCommentView и DeleteView.


В обоих классах пропишем поле template_name, в котором пропишем шаблон для страницы редактирования и страницы удаления комментария.

В классе EditCommentView дополнительно пропишем поле form_class, как в классе добавления комментария.


Код классов:

class EditCommentView(BaseCommentView, UpdateView):  
form_class = CommentForm
template_name = "blog/comment_edit.html"


class DeleteCommentView(BaseCommentView, DeleteView):
template_name = "blog/comment_delete.html"


Маршруты представлений.
Для всех трёх представлений осталось создать маршруты. Для этого откроем файл urls.py и в список urlpatterns добавим следующие строки:


path("comment/add/<int:pk>/", views.AddCommentView.as_view(), name="add_comment"),  
path(
"comment/edit/<int:pk>/", views.EditCommentView.as_view(), name="edit_comment"
),
path(
"comment/delete/<int:pk>/",
views.DeleteCommentView.as_view(),
name="delete_comment",
),


Шаблоны комментариев.
Начнём с основного шаблона вывода комментариев.


Шаблон добавления и вывода комментариев.
В директории с шаблонами создадим новый файл comments.html.

В нём пропишем шаблон для отображения комментариев:
🔥1
<div class="row">
<h2 class="mt-3 mb-3">Добавить комментарий:</h2>
{% if user.is_authenticated %}
<form method="post" enctype="multipart/form-data" action="{% url "blog:add_comment" pk=post.pk %}">
{% csrf_token %}
{{ comment_form.comment }}
<button class="btn btn-outline-warning mt-3" type="submit">Отправить</button>
</form>
{% else %}
<p><a href="{% url 'user_app:login' %}">Войдите</a> чтобы добавить комментарий.</p>
{% endif %}
</div>

<div class="row">
<h2 class="mt-3 mb-3">Комментарии пользователей:</h2>
{% if comments %}
{% for comment in comments %}
<p><a href="{% url 'user_app:user_profile' username=post.author %}">{{ comment.user }}</a>
| {{ comment.created_at }} | {% if comment.user user or user.is_superuser %}
<a href="{% url 'blog:edit_comment' comment.pk %}">Редактировать</a> |
<a href="{% url 'blog:delete_comment' comment.pk %}">Удалить</a>
{% endif %}</p>
<p>{{ comment.comment }}</p>
<hr>
{% endfor %}
{% else %}
<p>Нет комментариев</p>
{% endif %}
</div>

В первом блоке выводим форму для добавления комментария. Обратите внимание, что в форме передаём аргумент action с маршрутом на представление добавления комментария.

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

Далее откроем шаблон страницы поста и в удобное место подключим файл шаблона комментариев, передав в него объект поста и список комментариев:


{% include "blog/modules/comments.html" with post=post comments=post.comments.all%}


Шаблон редактирования комментария.
Создадим файл comment_edit.html и пропишем следующий код:


{% extends 'blog/base.html' %}
{% block noscript %}Редактирование комментария{% endblock %}

{% block content %}
<div class="form-section container mt-3">
<h2>Редактирование комментария</h2>
<form method="post">
{% csrf_token %}
<p>{{ form.comment }}</p>
<button class="btn btn-primary" type="submit">Обновить</button>
<a href="{% url 'blog:post_page' slug=object.post.slug category_slug=object.post.category.slug %}"
class="btn btn-secondary">Отмена</a>
</form>
</div>
{% endblock %}


Шаблон удаления комментария.
Создадим файл comment_delete.html и пропишем следующий код:


{% extends 'blog/base.html' %}
{% block noscript %}Удаление комментария{% endblock %}

{% block content %}
<div class="form-section container mt-3">
<h2>Удаление комментария</h2>
<p>Вы действительно хотите удалить этот комментарий?</p>
<pre>{{ object.comment }}</pre>
<form method="post">
{% csrf_token %}
<button class="btn btn-danger me-2" type="submit">Да, удалить</button>
<a href="{% url 'blog:post_page' slug=object.post.slug category_slug=object.post.category.slug %}"
class="btn btn-secondary">Отмена</a>
</form>
</div>
{% endblock %}


Заключение.
🔥3👍1
Добавить комментарии несложно. Куда сложнее будет далее за ними следить. Хоть у нас и есть "защита" в виде ограничения на зарегистрированных пользователей, спамеры "не дремлют", и, возможно, в будущем придётся добавлять защиту в виде капчи или что-то другое.



Файлы к посту, можно получить в боте по коду: 279348

Пост на сайте
Поддержать проект

#Python #Django #Гайды #Модели #Представления #Формы #Комментарии
🔥3
Всем привет!

За несколько дней произошло несколько событий.

Начнём с главного.

19-го января у моей группы в GB прошла итоговая аттестация (защита диплома). Нам обещали в течении месяца выслать диплом и номер его отслеживания... Видимо в GB месяц длится иначе, т.к. диплом я и мои одногруппники начали получать только с этой недели... Получив оповещение от Почты России о прибытии письма. 2.5 месяца на изготовление, отправки, но прикол не в этом! Теперь они предоставляют дипломы в виде двух листочков, без корочки. Ну да ладно, я уже на WB выбрал обложку)

И вот казалось бы, диплом, наконец-то эпопея длительностью в 1.5 года + 2.5 месяца ожидания диплома подошли к концу, надо радоваться... А радости то нет. И ощущения "дипломированного специалиста" тоже. Такие дела.

Второе "событие", опишу позже. там тоже есть приколы)
🔥7👏21
Добрый вечер, друзья!

Пятница - время для отдыха и развлечений. Подготовьте уютное место, закуски и напитки, чтобы создать атмосферу настоящего кинотеатра прямо у себя дома. Готовьтесь к запредельным приключениям и не забудьте приглушить свет - ведь именно в темноте ужасы кажутся еще более реальными. Наслаждайтесь вечером и пусть этот фильм подарит вам заряд адреналина на целую неделю!

Фильм: Зеркала

Год: 2008

Бывший нью-йоркский полицейский устраивается на работу ночным сторожем выгоревших руин крупного универмага. Обходя обугленные развалины, он начинает замечать что-то зловещее в декоративных зеркалах, украшающих стены: в огромных мерцающих стёклах отражается что-то жуткое.

https://www.sspoisk.ru/film/263447/

Приятного просмотра!
🔥2😱1