Код на салфетке
2.22K subscribers
746 photos
14 videos
2 files
788 links
Канал для тех, кому интересно программирование на Python и не только.

Сайт: https://pressanybutton.ru/
Чат: https://t.iss.one/+Li2vbxfWo0Q4ZDk6
Заметки автора: @writeanynotes

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
Приветствую.
Давайте немного порешаем задачки.

Сегодняшнюю задачу, давали на одном из курсов в качестве домашней работы. Предлагаю решить её и вам.
Можно решать на любом удобном для вас языке, а также не возбраняется обсуждение.

Задача.
Представить поле для игры в "Крестики-Нолики", размером 3x3 в виде двумерного массива с числами, представляющими из себя состояние ячеек.

Доступно 4 состояния:
- 0 - пустая ячейка.
- 1 - ячейка с крестиком
- 2 - ячейка с ноликом
- 3 - резервное значение

Необходимо записать 9 значений в файл, но так, чтобы размер файла был равен трём байтам.

После чего, реализовать возможность прочесть файл и восстановить исходный двумерный массив.
Полезные инструменты - Переключатель цветовой темы в Bootstrap5

После запуска сайта, я получил несколько вопросов касательно переключателя цветовой темы на сайте, а именно, как он реализован.

Ответ прост - читайте документацию: https://getbootstrap.com/docs/5.3/customize/color-modes/

Но, если бы всё было так просто, не было бы вопросов и поста.

Пост будет без привязки к Django или к чему-либо ещё.

В качестве IDE для HTML я рекомендую использовать Visual Studio Code.
Скачать его можно по ссылке: https://code.visualstudio.com/
Благодаря плагинам, в нём удобно работать с HTML и CSS файлами. Именно на примере работы в нём и будет пост.
Подготовка.
Создайте директорию в которой будете работать и откройте её в VS Code.
Создайте в ней две директории: css и js. В этих директориях будут находится файлы Bootstrap.

Переходим по ссылке и скачиваем последнюю актуальную версию нажав по синей кнопке Download в первом же блоке Compiled CSS and JS.

В скачанном архиве будет также две директории, как те, которые создали ранее, но не спешите всё распаковывать!.
В директории css нас интересуют два файла - bootstrap.css и bootstrap.min.css, а в директории js - bootstrap.bundle.js и bootstrap.bundle.min.js.


В чём разница?
Обычный css/js файл (например, style.css или script.js) и min.css/js файл (например, style.min.css или script.min..js) представляют собой два разных способа организации и оптимизации кода CSS/JS.

1. Обычный CSS/JS файл:
- Содержит человекочитаемый код с комментариями и форматированием.
- Используется во время разработки и обслуживания сайта.
- Размер файла может быть больше из-за комментариев и дополнительного форматирования.
2. Min CSS/JS файл:
- Является минифицированной (сжатой) версией файла.
- Отсутствуют комментарии и лишние пробелы.
- Используется для оптимизации загрузки и ускорения работы веб-страницы.
- Размер файла обычно меньше, чем размер обычного файла, благодаря удалению ненужных символов.

Выбирайте тот вариант, который вам удобнее и помещайте в соответствующую директорию. Я выбрал min версии, поскольку не планирую вносить правки в файлы Bootstrap.
Для тех, кто знакомится с Bootstrap лучше подойдёт полная версия. Можно будет посмотреть как реализованы те или иные классы, код JavaScript.


Собственный файл скрипта.
Помимо файла скриптов от Bootstrap, нам нужен и собственный.

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


Нужно ли скачивать Bootstrap?
Один из самых частых вопросов - нужно ли скачивать файлы локально, если их можно подключить по ссылке?
Ответ - не обязательно.

Подключение по ссылке может ускорить работу сайта за счёт CDN.
CDN выбирает ближайший сервер к пользователю и отдаёт оттуда файл. Но может и замедлить, если сервер сайта находится ближе, а CDN далеко.

И ещё одна актуальная проблема - блокировки интернет ресурсов. Если CDN будет заблокирован для пользователя или пользователь заблокирован на CDN - файл не будет загружен и это вызовет проблемы с отображением сайта.

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


Подключаем Bootstrap.
Начнём с самого начала - создания html файла и подключения Bootstrap5.
Создадим файл index.html.
В файле пишем символ восклицательного знака ! и нажимаем клавишу tab. Это создаст базовую структуру.

Для подключения CSS, в блоке тега head добавляем строку:
<link href="css/bootstrap.min.css" rel="stylesheet">


Тут мы указываем путь к файлу bootstrap.min.css и сообщаем, что это таблица стилей.


Для подключения JavaScript от Bootstrap и наш собственный, в конце блока тега body добавляем строки:
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/script.js"></script>


Тут указываем путь к файлу bootstrap.bundle.min.js и нашему script.js.

Вот и всё. Bootstrap подключен к странице (сайту).


JavaScript смены цветовой темы.
Для того, чтобы цветовая тема изменялась и, что немаловажно, запоминалась, необходим JavaScript код.

Откроем файл script.js и пропишем код предоставленный разработчиками Bootstrap:
Код примера ищите в файле script-dev.js в архиве с материалами к посту.
Описание функций:
1. getStoredTheme и setStoredTheme - это функции для чтения и записи темы в локальное хранилище браузера.
2. getPreferredTheme - эта функция сначала проверяет, есть ли тема в локальном хранилище. Если нет, она проверяет предпочтения пользователя на темную тему в настройках системы.
3. setTheme - эта функция устанавливает тему в качестве атрибута data-bs-theme в элементе document.documentElement (обычно это <html> ). Если тема 'auto' и пользователь предпочитает темную тему, устанавливается темная тема, иначе устанавливается выбранная тема.
4. showActiveTheme - эта функция обновляет пользовательский интерфейс для отображения активной темы. Она делает кнопку выбранной темы активной и устанавливает соответствующую иконку темы.
5. Последний блок кода добавляет обработчик событий к window.matchMedia('(prefers-color-scheme: dark)') . Если пользователь изменяет предпочтение на темную тему в системных настройках, код проверяет, не установлена ли уже темная или светлая тема. Если нет, он устанавливает предпочитаемую тему.


Добавляем переключение цветовой темы.
Теперь нужно добавить в шаблон метку текущей цветовой темы и переключатель.

Для того, чтобы Bootstrap понял, какая цветовая тема в данный момент используется, в самом начале файла, внутри тега html, сразу после lang="en" добавим метку текущей темы - data-bs-theme="dark".
Должно быть вот так:
<html lang="en" data-bs-theme="dark">


Затем нужно добавить переключатель.

Вариант из документации.
Разработчики подготовили пример шапки с переключателем цветовой темы в виде выпадающего списка.
Подробнее можно ознакомиться в документации на GitHub: https://github.com/twbs/examples/tree/main/color-modes

Добавляем следующий код в блок body до подключения JS файлов:
Код примера ищите в файле index-dev.html в архиве с материалами к посту.


Открываем файл index.html в браузере, для этого можно нажать кнопку Go Live в нижней-правой части окна VS Code.

На открывшейся странице увидим пример шапки и переключатель темы. Он должен корректно отрабатывать переключение темы.


Мой вариант.
У себя на сайте, я сделал кнопку вида switch. Как по мне, такой вариант органичнее выглядит.

В теге body до подключения JS файлов добавим следующий код:
Код примера ищите в файле index-my.html в архиве с материалами к посту.


В директории css создадим файл style.css и подключим его в теге head:
<link href="css/style.css" rel="stylesheet">


В файле напишем стили для переключателя, добавляющие иконки по краям:
.switch-icons {
display: flex;
align-items: center;
flex-wrap: nowrap;
padding: 0;
margin: 0;
}

.switch-icons::before {
content: url(../svg/sun-fill.svg);
width: 24px;
height: 24px;
margin-right: 3px;
filter: invert(1);
}

.form-check-label {
content: url(../svg/moon-stars-fill.svg);
width: 12px;
height: 12px;
margin-left: 8px;
filter: invert(1);
}

.form-switch .form-check-input {
margin: 0;
}

Иконки приложены к материалам поста

Изменению также подвергся и JS код:
Код примера ищите в файле csript-my.js в архиве с материалами к посту.


Откройте страницу в браузере и проверьте, как отрабатывает переключатель.

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

Файлы к посту, можно получить в боте по коду: 166197
👍1
Так и запишем - задача не вызвала вообще никакой реакции.

Сегодня будет простая викторина.. Какой командой можно создать новый проект в Django?
Anonymous Quiz
25%
python manage.py createproject myproject
46%
django-admin startproject myproject
4%
django-admin newproject myproject
14%
python manage.py projectstart myproject
11%
django-admin createproject myproject
🔥2
Какой командой можно создать новое приложение в Django?
Anonymous Quiz
12%
django-admin appstart myproject
16%
python manage.py newapp myproject
60%
python manage.py startapp myproject
4%
django-admin projectapp myproject
8%
python manage.py app myproject
🔥1
Django 27.1 Представления на основе классов

В предыдущих постах я рассказывал о представлениях на основе функций, они же function-based views или FBV.

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


Классовые представления.
Классовые представления, они же class-based views или CBV. Представляют собой альтернативный подход к созданию представлений. Они основаны на использовании классов вместо функций, что позволяет лучше структурировать код и повысить его переиспользование.

Классовые представления в Django обеспечивают ряд преимуществ по сравнению с функциональными представлениями. Они позволяют использовать принципы ООП, такие как наследование и полиморфизм, что делает код более организованным и поддерживаемым.
Классы-представления могут быть очень гибкими и настраиваемыми. Можно определить свои собственные классы-представления, которые наследуются от базовых классов и расширяют их функциональность в соответствии с требованиями проекта. Это позволяет сократить дублирование кода, упростить его поддержку и улучшить его читабельность.

При использования классов-представлений можно определить методы, такие как get(), post(), которые обрабатывают соответствующие типы запросов. В функциональном представлении, это повлекло бы за собой цепочку if-elif условий для обработки нужного типа запроса в представлении.

Различия между функциональными и классовыми представлениями:
1. Структура кода: В функциональных представлениях код разбит на функции, которые выполняют определенные действия. В классовых представлениях код организован в виде классов, которые содержат методы для обработки запросов.
2. Наследование: В классовых представлениях можно использовать наследование, что позволяет переиспользовать код и добавлять новую функциональность. В функциональных представлениях такая возможность отсутствует.
3. Расширяемость: Классовые представления позволяют легко добавлять новые методы и функциональность без изменения основного кода. В функциональных представлениях это может быть сложнее.
4. Миксины: Классовые представления поддерживают использование миксинов, которые представляют собой классы с определенными методами, которые можно добавить к основному классу представления для расширения его функциональности.
5. Читаемость кода: Классовые представления могут быть более читаемыми и понятными, особенно для разработчиков, знакомых с объектно-ориентированным программированием.


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

Вот некоторые из них:
1. View: Это самый базовый класс представления в Django. Он обрабатывает связывание представления с URL, диспетчеризацию методов HTTP и другие общие функции. Все другие классы представлений Django наследуются от этого класса.
2. TemplateView: Этот класс представления используется, когда вам нужно просто отобразить страницу, которая не требует никакой дополнительной логики. Он автоматически рендерит указанный шаблон.
3. ListView: Это класс представления, который используется для отображения списка объектов. Он автоматически предоставляет контекст для шаблона, который содержит список объектов.
4. DetailView: Этот класс представления используется для отображения деталей конкретного объекта. Он автоматически предоставляет контекст для шаблона, который содержит объект.
5. CreateView, UpdateView, DeleteView: Эти классы представлений используются для создания, обновления и удаления объектов соответственно. Они автоматически предоставляют форму для ввода данных и обрабатывают POST-запросы для создания, обновления или удаления объектов.
6. FormView: Этот класс представления используется для отображения и обработки форм. Он автоматически предоставляет форму для ввода данных и обрабатывает POST-запросы.
7. RedirectView: Этот класс представления используется для перенаправления на другой URL.
8. DateDetailView, YearArchiveView, MonthArchiveView, DayArchiveView, TodayArchiveView: Эти классы представлений предназначены для отображения архивов объектов, отсортированных по датам.

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


Теории много, но без неё было никак. В следующей части начнём переделывать представления из функциональных в классовые.
🔥3
Django 27.2 Представления на основе классов - Практика

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

На данный момент у меня в проекте 4 представления, а именно:
- Главная страница
- Страница категории
- Страница поста
- Страница тега

Откроем файлы views.py и urls.py.
Представление главной страницы.
Вот так представление выглядит на данный момент:
def index(request):  
categories_list = models.CategoryModel.objects.all()
latest_posts = models.PostModel.post_manager.latest_posts()

context = {
'categories_list': categories_list,
'latest_posts': latest_posts,
}

return render(request,
'blog/index.html',
context)

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

Для того, чтобы переписать это в классовый вид, создадим новый класс IndexView и унаследуем его от TemplateView.

В классе пропишем единственное поле - template_name и присвоим ему строку с путём до шаблона главной страницы.

Также в классе будет всего один метод - get_context_data, принимающий self и набор именованных аргументов **kwargs.
В теле метода, получим из родительского класса экземпляр контекста, представляющий собой словарь.

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

В конце делаем возврат контекста.

Код:
from django.views.generic import TemplateView


class IndexView(TemplateView):
template_name = 'blog/index.html'

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['categories_list'] = models.CategoryModel.objects.all()
context['latest_posts'] = models.PostModel.post_manager.latest_posts()
return context

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


URL-паттерн главной страницы.
У нас уже есть паттерн для главной страницы:
path('', views.index, name='index'),

Он ведёт на функцию, для класса, его необходимо слегка изменить, а именно поменять имя функции index на имя класса IndexView и добавить обращение к методу as_view(), сообщающему, что мы обращаемся к классу-представлению.
path('', views.IndexView.as_view(), name='index'),


Представление страницы категории.
Сейчас представление выглядит так:
def category_page(request, category_slug):  
category = models.CategoryModel.objects.get(slug=category_slug)
descendant_categories = category.get_descendants(include_self=True)
posts = models.PostModel.objects.filter(category__in=descendant_categories)
categories_list = models.CategoryModel.get_children(self=category)

context = {
'category': category,
'posts': posts,
'categories_list': categories_list,
}

return render(request,
'blog/category_page.html',
context)

Для вывода списка постов на странице категории будем использовать ListView.
Создадим класс CategoryPageView, который наследует `ListView`.

В данном классе будет 3 поля, 2 переопределённых метода и один собственный метод.


Поля класса.
Первое поле model, в нём мы передаём ссылку на модель, с которой будет представление. В нашем случае это модель поста.
Второе поле, как и в предыдущем классе - template_name.
В третьем поле context_object_name, мы определяем то, как будет называться переменная к которой мы обращаемся в шаблоне, у нас это - posts.


Собственный метод.
В нашем классе мы создадим собственный метод get_category, возвращающий объект текущей категории.
Это сделано для избегания повторных обращений к базе данных, для получения объекта текущей категории в переопределённых методах.

Логика проста, мы не задали поле класса для хранения объекта категории. При обращении к методу, проиводится проверка, существует или нет поле с именем category.
Если поле существует, возвращается его значение.
Если поле не существует, то оно создаётся и в него мы присваиемаем полученные из БД данные.
Обратите внимание, PyCharm и возможно другие IDE будут сигнализировать, что в классе не задано поле category, игнорируем сообщение, поскольку именно в этом и смысл.


Переопределённые методы.
В предыдущем классе, мы переопределили только один метод get_context_data, переопределим его и в этом классе.

В методе добавим в контекст объект текущей категории и список подкатегорий.

Вторым переопределённым методом, будет метод get_queryset, необходимый для создания списка объектов, в нашем случае постов относящихся к этой и вложенным категориям. Об этом я подробно рассказывал в посте про создание представления страницы категории.

Код.
from django.views.generic import ListView


class CategoryPageView(ListView):
model = models.PostModel
template_name = 'blog/category_page.html'
context_object_name = 'posts'

def get_queryset(self):
category = self.get_category()
descendant_categories = category.get_descendants(include_self=True)
return models.PostModel.objects.filter(category__in=descendant_categories)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_category()
context['category'] = category
context['categories_list'] = models.CategoryModel.get_children(self=category)
return context

def get_category(self):
if not hasattr(self, 'category'):
self.category = models.CategoryModel.objects.get(slug=self.kwargs['category_slug'])
return self.category


По аналогии с предыдущим классом, измените URL-паттерн.
path('category/<slug:category_slug>/', views.CategoryPageView.as_view(), name='category_page'),


Представление страницы поста.
Сейчас представление выглядит так:
def post_page(request, category_slug, slug):  
post = get_object_or_404(models.PostModel, slug=slug)
post.views += 1
post.save()

context = {
'post': post,
}

return render(request,
'blog/post_page.html',
context)

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

Создадим класс PostPageView, наследующий DetailView и пропишем такие же как в классе страницы категории, поля, а именно - model, template_name и context_object_name.

Переопределим метод get_object.
В этом методе мы будем получать объект текущего поста и увеличивать счётчик просмотров на 1.
Метод будет вызываться автоматически при открытии поста.

Код.
from django.views.generic import DetailView


class PostPageView(DetailView):
model = models.PostModel
template_name = 'blog/post_page.html'
context_object_name = 'post'

def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
obj.views += 1
obj.save()
return obj

И изменим URL-паттерн:
path('post/<slug:category_slug>/<slug:slug>/', views.PostPageView.as_view(), name='post_page'),


Представление страницы тега.
Последнее, четвёртое представление. Сейчас оно такое:
def tag_page(request, tag_name):  
posts = models.PostModel.objects.filter(tags__slug=tag_name).distinct()

context = {
'tag_name': tag_name,
'posts': posts,
}

return render(request,
'blog/tag_page.html',
context)

Последний, самый простой, в том плане, что он такой же как и представление категории.

Создаём класс TagPageView, унаследованный от ListView.
В классе прописываем три поля, как в предыдущие два раза.

Переопределяем метод get_queryset, возвращающий посты относящиеся к текущему тегу.

Переопределяем метод get_context_data, добавляя в контекст объект текущего тега.
Код.
class TagPageView(ListView):  
model = models.PostModel
template_name = 'blog/tag_page.html'
context_object_name = 'posts'

def get_queryset(self):
tag_name = self.kwargs['tag_name']
return models.PostModel.objects.filter(tags__slug=tag_name).distinct()

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tag_name'] = self.kwargs['tag_name']
return context


И конечно же, URL-паттерн:
re_path(r'^tag/(?P<tag_name>[\w-]+)/$', views.TagPageView.as_view(), name='tag_page'),



Теперь, если запустить Django, то всё будет как прежде.

Файлы к посту, можно получить в боте по коду: 546974
🔥1
Состоялся релиз третьей версии AIOgram.

Обновить версию можно с помощью PyPI: pip install -U aiogram.
Но имейте в виду, что в этой версии есть много критических изменений относительно второй версии.

В связи с этим, я подготовил перевод документации по миграции со второй на третью версию библиотеки.
Ознакомиться с материалом можно на сайте.
🔥3
Было две викторины, на тему создания Django проекта и Django приложения.
Результаты следующие:
- Создание Django проекта - 46% верных ответов среди 28 участвующих.
- Создание Django приложения - 58% верных ответов среди 24 участвующих.

В связи с этим небольшой пост, по созданию проекта и приложения с кратким описанием структуры.
🔥1
Создание Django проекта
Чтобы создать проект в Django, нам нужно открыть терминал и перейти в папку, где мы хотим создать наш Django проект.

Здесь мы запускаем команду:

django-admin startproject myproject


Эта команда создаст для нас новый каталог, названный myproject, и заполнит его файлами, необходимыми для создания проекта Django.


Структура проекта Django
Давайте рассмотрим структуру директорий и файлов, созданных командой startproject.

myproject/
|-- myproject/
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| |-- asgi.py
| `-- wsgi.py
`-- manage.py


- myproject/ - это каталог верхнего уровня, который содержит наш Django проект.
- myproject/myproject/ - это каталог, который содержит первое Django приложение.
- myproject/__init__.py - пустой файл, который просто говорит Python, что каталог myproject должен рассматриваться как Python-пакет.
- myproject/settings.py - - файл, содержащий настройки Django-проекта, такие как база данных, интернационализация, часовой пояс, а также другие настройки.
- myproject/urls.py - - файл, содержащий шаблоны URL-адресов проекта Django. Как только вы определите эти шаблоны, Django будет использовать их для пересылки пользователей на соответствующее представление.
- myproject/asgi.py и myproject/wsgi.py - файлы, содержащие настройки для ASGI и WSGI серверов. ASGI - это новый способ работы с асинхронным Python, в то время как WSGI - это протокол для связи Python-приложений и веб-сервера.
- manage.py - исполняемый файл, который используется для запуска различных команд в веб-приложении Django, например запуска сервера разработки, создания миграций базы данных и многое другое.


Создание приложения в Django
Для создания нового приложения в Django необходимо запустить следующую команду из терминала:

python manage.py startapp my_app


Где my_app - это название нового приложения.

После выполнения этой команды Django создаст новый каталог с именем my_app внутри вашего проекта. В этом каталоге будут находиться необходимые файлы для создания нового приложения.


Структура приложения Django
Рассмотрим структуру каталогов и файлов, которые были созданы при выполнении команды startapp:

my_app/
|-- __init__.py
|-- admin.py
|-- apps.py
|-- models.py
|-- tests.py
`-- views.py


- __init__.py - пустой файл, который указывает Python, что каталог my_app должен рассматриваться как Python-пакет.
- admin.py - файл, содержащий настройки администраторской панели (Django Admin) для вашего приложения.
- apps.py - файл, содержащий настройки приложения, такие как его название.
- models.py - файл, содержащий определения моделей для вашего приложения. Модели - это объектно-реляционная отображаемая таблица базы данных.
- tests.py - файл, содержащий модули тестирования для вашего приложения.
- views.py - файл, содержащий определения представлений (views) для вашего приложения. В этих представлениях определено, что происходит, когда пользователь переходит на страницу вашего сайта.
👍6
Django 28. Добавляем пагинацию на сайт

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

Пагинация позволяет ускорить загрузку страниц за счёт сегментирования содержимого, а также улучшить взаимодействие пользователя с сайтом.

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

Разберём оба варианта.
🔥2
Изменение представлений.

Пагинация в CBV.
В прошлом посте я писал о преимуществах классовых представлений от функциональных. И если в моём случае, в коде преимущество не видно сразу, то с пагинацией наоборот.

Для добавления пагинации в данные страницы достаточно добавить в код представления буквально одно поле - paginate_by с указанием количества элементов на страницу.

На примере класса страницы тегов:
class TagPageView(ListView):  
model = models.PostModel
template_name = 'blog/tag_page.html'
context_object_name = 'posts'
paginate_by = 10

# методы класса

Пагинация в FBV.
В функциональных представлениях пагинация добавляется немного другим способом.

В функции представления необходимо добавить три переменные.
1. paginator - ей присваиваем объект класса Paginator, передавая в него переменную со списком постов и количество элементов на страницу.
2. page_number - в неё получаем значение текущей страницы, если его нет, то по умолчанию устанавливаем 1 страницу.
3. posts - переменная, в которую получаем список постов для конкретной страницы

На примере функции страницы тегов:
from django.core.paginator import Paginator


def tag_page(request, tag_name):
posts_list = models.PostModel.objects.filter(tags__slug=tag_name).distinct()

paginator = Paginator(posts_list, 10)
page_number = request.GET.get('page', 1)
posts = paginator.page(page_number)

context = {
'tag_name': tag_name,
'posts': posts,
}

return render(request,
'blog/tag_page.html',
context)


Добавляем в шаблон.
После передачи данных в шаблон их нужно обработать.

Для оформления вывода будем использовать стили пагинатора из Bootstrap.

Перейдём в директорию шаблонов и создадим файл pagination.html. Для удобства можно создать директорию modules и поместить его туда.

В файле напишем три блока:
- Первый отвечает за кнопку назад, функционал и отображение.
- Второй за кнопки страниц.
- Третий за кнопку вперёд.

Код.
<nav aria-label="Page navigation">  
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}">Назад</a></li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Назад</span>
</li> {% endif %}

{% for num_page in page_obj.paginator.page_range %}
{% if num_page == page_obj.number %}
<li class="page-item active"><a class="page-link" href="#">{{ num_page }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ num_page }}">{{ num_page }}</a></li>
{% endif %}
{% endfor %}

{% if page_obj.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}">Вперед</a></li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Вперед</span>
</li> {% endif %}
</ul>
</nav>

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


Подключаем на странице.
Теперь этот файл необходимо подключить в шаблоне страницы, продолжим пример на странице тегов.
Откроем файл tag_page.html.

До закрытия тега div с классом container добавляем следующий блок:

Для CBV:
<div class="col-12">  
{% include "blog/modules/pagination.html" %}
</div>

Для FBV:
<div class="col-12">  
{% include "blog/modules/pagination.html" with page_obj=posts %}
</div>

Обратите внимание. Во втором случае, мы передаём в шаблон переменную posts под видом переменной page_obj. Этого можно и не делать, заменив в файле pagination.html все page_obj на posts

Теперь можно запустить Django и убедиться, что пагинация работает.

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