Django, django-filter и пагинация

Моя цель - иметь страницу 'user_profile', которая отображает соответствующую информацию об интересующем нас пользователе.

Кроме того, страница 'user_profile' должна включать все посты, которые были созданы соответствующим пользователем как новые записи в блоге.

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

На данный момент я использовал следующий подход:

filters.py

import django_filters

class AccountPostFilter(django_filters.FilterSet):
title = django_filters.CharFilter(lookup_expr='icontains')
category = django_filters.ChoiceFilter(choices=cat_list)

class Meta:
    model = Post
    fields = ['title', 'category']

views.py

class UserProfile(DetailView, MultipleObjectMixin):
model = Account
template_name = 'account/user_profile.html'
paginate_by = 5


def get_context_data(self, **kwargs):
    posts = Post.objects.all().filter(author=self.kwargs['pk'])
    context = super().get_context_data(object_list=posts, **kwargs)
    context['filterset'] = AccountPostFilter(self.request.GET, queryset=posts)

    return context

Большое спасибо за уделенное время. С наилучшими пожеланиями, Дэниел

Есть другой способ сделать это, и сделать это чисто и профессионально, что избавит вас от необходимости использовать Django Filters:

Создайте вспомогательную функцию clean_filters (Она поможет вам очистить фильтры, поступающие из браунселлера:

).
def clean_filters(filters):
    filters = {k: v for k, v in filters.items() if v}
    return filters

Создайте еще одну функцию помощи под названием search (она поможет вам получить параметры из GET-запроса и поместить их в **filters внутри директивы django filter. И возвращать их обратно с помощью пагинатора, чтобы вы могли сохранять те же фильтры при переходе от страницы к странице):

from 'your_utils_file' import clean_filters
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def search(request):
    filters = {
        "account__first_name__icontains": request.GET.get("fname_kw"), # put your filters here
        "account__last_name__icontains": request.GET.get("lname_kw"), # put your filters here
    }

    html_queries = {
        "fname_kw": request.GET.get("fname_kw"),
        "lname_kw": request.GET.get("lname_kw"),
    }

    filters = clean_filters(filters)
    html_queries = clean_filters(html_queries)

    posts = Post.objects.filter(**filters) # put your model here

    page = request.GET.get('page', 1)
    paginator = Paginator(posts, 8)
    try:
        posts= paginator.page(page)
    except PageNotAnInteger:
        posts= paginator.page(1)
    except EmptyPage:
        posts= paginator.page(paginator.num_pages)

    return posts

Вот ваше представление ( здесь просто вызывается функция поиска, чтобы уменьшить код вашего представления и облегчить его сопровождение):

def search_page(request):
    posts = search(request)

    if posts is not None:
        context = {
            'posts': posts,
        }
        return render(request, "core/index.html", context)
    return redirect("index")

Вот ваш HTML (просто классический код пагинации для Django и Bootstrap. Здесь также есть фильтр и значение фильтра в цикле внутри GET запроса):

<div class="mb-5">
{% if posts.has_other_pages %}
    <nav aria-label="Page navigation example">
        <ul class="pagination justify-content-center">
            {% if posts.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page={{ posts.previous_page_number }}{% for fil, fil_value in filters.items %}&{{fil}}={{fil_value}}{% endfor %}" tabindex="-1">
                    <i class="fa fa-angle-left"></i>
                    <span class="sr-only">Prev</span>
                </a>
            </li>
            {% else %}
            <li class="page-item disabled">
                <a class="page-link" href="javascript:void(0)" tabindex="-1">
                    <i class="fa fa-angle-left"></i>
                    <span class="sr-only">Prev</span>
                </a>
            </li>
            {% endif %}
            {% for i in posts.paginator.page_range %}
            {% if posts.number == i %}
                <li class="page-item active"><a class="page-link" href="javascript:void(0)">{{ i }}</a></li>
            {% else %}
                <li class="page-item"><a class="page-link" href="?page={{ i }}{% for fil, fil_value in filters.items %}&{{fil}}={{fil_value}}{% endfor %}">{{ i }}</a></li>
            {% endif %}
            {% endfor %}
            {% if posts.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{ posts.next_page_number }}{% for fil, fil_value in filters.items %}&{{fil}}={{fil_value}}{% endfor %}">
                    <i class="fa fa-angle-right"></i>
                    <span class="sr-only">Next</span>
                </a>
            </li>
            {% else %}
            <li class="page-item disabled">
                <a class="page-link" href="javascript:void(0)">
                    <i class="fa fa-angle-right"></i>
                    <span class="sr-only">Next</span>
                </a>
            </li>
            {% endif %}  
        </ul>
    </nav>
{% endif %}

Надеюсь, это поможет!

Вернуться на верх