Обзор
Мы собираемся разбить сообщения в блоге на страницы, используя общий класс ListView django. Модуль generics действительно предлагает множество классов, которые обеспечивают отличную функциональность, переопределяя пару атрибутов, это может сэкономить много времени и усилий, связанных с выполнением всего вручную внутри основанных на функциях представлений.
Эта модель является моделью публикации в блоге, используемой на этом веб-сайте. Это пример из реального мира.
Модель
Здесь мы определяем простую модель Tag and Post.
Мы также определяем простой QuerySet, чтобы предоставить простой способ фильтрации сообщений в блогах, которые мы действительно хотим показывать на нашем веб-сайте.
Определение QuerySet для этого более полезно, это похоже на get_absolute_url. Используя метод QuerySet для получения опубликованных и рекомендуемых сообщений в блогах, мы устраняем ручные запросы в кодовой базе. .
Если мы решим, как мы будем опубликовывать или популярные сообщения в блоге, единственное место, которое изменится, — это PostQuerySet и его методы.
models.py
class Tag(models.Model): """ Represents a blog post tag/category. """ name = models.CharField(max_length=255, blank=True)
def __str__(self): return self.name
class Meta: ordering = ["name"]
class PostQuerySet(models.QuerySet): """ Custom queryset manager for getting objects easily. """
def published(self): """ Returns only the published posts. """ return self.filter(is_published=True)
def featured(self): """ Returns only the published posts that are featured. """ return self.published().filter(is_featured=True)
class Post(models.Model): """ Represents a blog post. """
# ------------------------------------------ # Relationship Fields # ------------------------------------------
tags = models.ManyToManyField(Tag, related_name="post_tags")
author = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True )
# ------------------------------------------ # Attributes # ------------------------------------------
header = ProcessedImageField( upload_to="headers", format="JPEG", options={"quality": 70}, null=True, blank=True, )
image = ProcessedImageField( upload_to="images", format="JPEG", options={"quality": 70}, null=True, processors=[ResizeToFill(width=300, height=300)], blank=True, )
date = models.DateField(auto_now_add=True) slug = models.SlugField(max_length=255, unique=True) content = RichTextUploadingField(_("Content"), null=True, blank=True)
meta_title = models.CharField(max_length=255, blank=True) meta_desc = models.CharField(max_length=255, blank=True)
is_featured = models.BooleanField(default=False) is_published = models.BooleanField(default=False)
intro = models.CharField(max_length=255, blank=True) title = models.CharField(max_length=255, blank=True) sub_title = models.CharField(max_length=255, blank=True)
objects = PostQuerySet.as_manager()
def get_absolute_url(self): """ Returns the detail URL. """ return reverse("blog:detail", kwargs={"slug": self.slug})
def __str__(self): return self.title
class Meta: ordering = ["-date", "is_featured"]
Пагинация в поле зрения
Теперь мы можем создать URL-адрес и вид, чтобы вернуть список постов в блоге с разбивкой на страницы.
Это действительно простой код, который позволяет фильтровать сообщения блога на основе некоторых простых параметров запроса. Для более сложной фильтрации следует использовать django-filter.
urls.py
from django.urls import path from .views import BlogList
app_name = "blog"
urlpatterns = [ path("", BlogList.as_view(), name="list"), ]
views.py
class BlogList(ListView): model = Post paginate_by = 10 context_object_name = "posts" template_name = "blog/list.html" queryset = ( Post.objects.published().select_related("author").prefetch_related("tags") )
def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs)
featured = self.get_queryset().filter(is_featured=True)
context["featured"] = featured
return context
def get_queryset(self): querydict = self.request.GET
tag = querydict.get("tag") title = querydict.get("title") author = querydict.get("author")
qs = super().get_queryset()
if tag: qs = qs.filter(tags__exact=tag)
if title: qs = qs.filter(title__contains=title)
if author: qs = qs.filter(author_id=author)
return qs
Давайте разберем общий ListView
- Мы сообщаем ему, какую модель мы используем, с помощью атрибута model.
- Мы сообщаем ему размер страницы через атрибут paginate_by.
- Мы даем нашим объектам собственное контекстное имя с помощью атрибута context_object_name.
- Мы сообщаем ему, какой шаблон отображать, с помощью атрибута template_name.
- Мы даем ему набор запросов, который он может вызывать через атрибут queryset.
Мы переопределили 2 метода:
get_queryset
- Мы сделали это, потому что хотели добавить пользователям возможность фильтровать сообщения блога на основе: [название, тег, author_id]
get_context_data
- Мы также хотели отправлять избранные сообщения в шаблон с помощью ключа «featured».
Разбивка на страницы в шаблоне
Здесь мы в основном перебираем наше context_object_name, которое публикует, и создаем список сообщений. Затем у нас есть дополнительный вход, который позволяет фильтровать заголовок и избранные сообщения.
Вы можете легко создать частичную разбивку на страницы, которая принимает page_obj и paginator, чтобы один раз создать HTML для разбивки на страницы и иметь единообразный стиль пагинации на всем веб-сайте.
блог/list.html
{% block content %}
<section class="site-section"> <div class="container"> <div class="row">
<div class="col-md-8"> <div class="row mb-5">
{% for post in posts %}
<div class="col-md-6 col-lg-6 mb-4 mb-lg-4"> <a href="{{ post.get_absolute_url }}"> <div class="h-entry"> <img src="{{ post.image.url }}" alt="Image" class="img-fluid"> <h2 class="font-size-regular"> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> </h2> <div class="meta mb-4"><a href="{% url 'blog:list' %}?author={{ post.author.id }}">{{ post.author.name }}</a> <span class="mx-2">•</span>{{ post.date }}<span class="mx-2">•</span> {% for tag in post.tags.all %} <a href="{% url 'blog:list' %}?tag={{ tag.id }}">{{ tag.name }}</a>• {% endfor %} </div> <p>{{ post.intro }}</p> </div> </a> </div> {% endfor %}
</div>
<div class="row"> <div class="col-12">
<ul class="pagination">
{% if page_obj.has_previous %} <li class="page-item"> <a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> <span class="sr-only">Previous</span> </a> </li> {% endif %}
{% for i in paginator.page_range %} {% if page_obj.number == i %} <li class="page-item active"> <span class="page-link"> {{ i }} <span class="sr-only">(current)</span> </span> </li> {% else %} <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li> {% endif %} {% endfor %}
{% if page_obj.has_next %} <li class="page-item"> <a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> <span class="sr-only">Next</span> </a> </li> {% endif %}
</ul>
</div> </div> </div>
<div class="col-md-3 ml-auto"> <div class="mb-5"> <h3 class="h5 text-black mb-3">Search</h3> <form action="{% url 'blog:list' %}" method="GET"> <div class="form-group d-flex"> <input type="text" class="form-control" name="title" id="title" placeholder="Search keyword and hit enter..."> </div> </form> </div>
<div class="mb-5"> <h3 class="h5 text-black mb-3">Featured Posts</h3> <ul class="list-unstyled"> {% for post in featured %} <li class="mb-2"> <a href="{{ post.get_aboslute_url }}">{{ post.title }}</a> </li> {% endfor %} </ul> </div> </div>
</div> </div> </section>
{% endblock %}
Результат
Вывод
Разбивка на страницы в django очень проста. Использование дженериков django также делает написание кода более продуктивным. В конце концов, django — это фреймворк для перфекционистов с дедлайном.
Мы предлагаем Django Consulting в качестве услуги для клиентов, которые хотят улучшить свои приложения Django, и людей, которые хотят создать веб-сайт компании.