Обзор

Мы собираемся разбить сообщения в блоге на страницы, используя общий класс 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

  1. Мы сообщаем ему, какую модель мы используем, с помощью атрибута model.
  2. Мы сообщаем ему размер страницы через атрибут paginate_by.
  3. Мы даем нашим объектам собственное контекстное имя с помощью атрибута context_object_name.
  4. Мы сообщаем ему, какой шаблон отображать, с помощью атрибута template_name.
  5. Мы даем ему набор запросов, который он может вызывать через атрибут 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">&bullet;</span>{{ post.date }}<span class="mx-2">&bullet;</span>
                      {% for tag in post.tags.all %}
                        <a href="{% url 'blog:list' %}?tag={{ tag.id }}">{{ tag.name }}</a>&bullet;
                      {% 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">&laquo;</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">&raquo;</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, и людей, которые хотят создать веб-сайт компании.