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 %}
Надеюсь, это поможет!