web-dev-qa-db-ja.com

django-filterはページネーションを使用します

Django-filter マイリストビューで検索機能を提供するパッケージ。

次に、そのビューにもページネーションを追加したいと思います。
ページネーションをフィルタリングされたクエリセットに結合しようとしていますが、どうすればよいかわかりません。

これまでのところ、views.py

def search(request):
    qs = local_url.objects.filter(global_url__id=1).all()
    paginator = Paginator(qs, 25)
    page = request.GET.get('page')
    try:
        pub = paginator.page(page)
    except PageNotAnInteger:
        pub = paginator.page(1)
    except EmptyPage:
       pub = paginator.page(paginator.num_pages)
    url_filter = PublicationFilter(request.GET, queryset=qs)
    return render(request, 'ingester/search_list.html', {'filter': url_filter, 'publication':pub})
15
Anh Tuan Nguyen

これは私のために働きました:

これを使用する代わりに私のテンプレートで

<li><a href="?page={{ i }}">{{ i }}</a></li>

私はこれを書きました:

{% if 'whatever_parameter_you_use_to_filter' in request.get_full_path %}
   <li><a href="{{ request.get_full_path }}&page={{ i }}"{{ i }}</a></li>
{% else %}
   <li><a href="?page={{ i }}">{{ i }}</a></li>
{% endif %}

それが役に立てば幸いです:)

5
stathoula

この問題を修正するためのDRYerとクリーナーのソリューションを見つけるのに少し時間がかかりました。私の意見では、テンプレートタグを使用するのが最善の方法です。

from Django import template

register = template.Library()

@register.simple_tag
def relative_url(value, field_name, urlencode=None):
    url = '?{}={}'.format(field_name, value)
    if urlencode:
        querystring = urlencode.split('&')
        filtered_querystring = filter(lambda p: p.split('=')[0] != field_name, querystring)
        encoded_querystring = '&'.join(filtered_querystring)
        url = '{}&{}'.format(url, encoded_querystring)
    return url

そしてあなたのテンプレートで

<a href="{% relative_url i 'page' request.GET.urlencode %}">{{ i }}</a>

ソース: QueryStringパラメータを使用した処理

3

ここで最も重要な部分はテンプレートでURLを作成する方法です。

あなたはおそらく持っている

{% if pages.has_previous %}
<li><a href="?page={{ pages.previous_page_number }}">Prev</a></li>
{% endif %}

最初のページ分割された結果を切り替えるためにそれだけを使用している場合、これは完全に問題ありません。

ただし、トリッキーな部分は、Django-fitlerフィルターを使用する場合、クエリ文字列('?'の後の部分)が?page=2を無視して、まったく新しいキーと値のペアを取得することです。同様。

したがって、フィルタリングされた結果でページ分割を機能させるには、[次へ]または[前へ]ボタンをクリックするときに、Django-fitlerのKey-Valueの中で、&page=5をペアとして渡す必要があります。

@stathoulaが述べたように、クエリ文字列に少なくとも1つのフィルターフィールドが既に存在するかどうかを確認する必要があります。そうである場合は、すでに存在するキーと値のペアを使用し、その後に新しい&page=3ペアを使用する必要があります。

非常にシンプルに見えますが、ユーザーが矢印をクリックしながらクエリ文字列内で&page=1を何度も繰り返さないように、小さなハックを実行する必要がありました。

私の場合は「タイトル」をフィルターとして使用しているので、すでにそこにあるかどうかを確認する必要があります。

これが、私のプロジェクトで完璧に機能するようにしたものの断片です。

templates/pagination.html

<div class="paginator">

    {% with request.get_full_path as querystring %}
        <ul class="pagination nav navbar-nav">

            <!-- Previous page section -->
            {% if pages.has_previous %}
                {% if 'title' in querystring %}
                    {% if 'page' in querystring %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring|slice:":-7" }}&page={{ pages.previous_page_number }}">Prev</a>
                        </li>
                    {% else %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring }}&page={{ pages.previous_page_number }}">Prev</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="paginator {% if pages.number == page %}active{% endif %}">
                        <a href="?page={{ pages.previous_page_number }}">Prev</a>
                    </li>
                {% endif %}
            {% endif %}

            <!-- All pages section -->
            {% for page in pages.paginator.page_range %}
                {% if 'title' in querystring %}
                    {% if 'page' in querystring %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring|slice:":-7" }}&page={{ page }}">{{ page }}</a>
                        </li>
                    {% else %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring }}&page={{ page }}">{{ page }}</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="paginator {% if pages.number == page %}active{% endif %}">
                        <a href="?page={{ page }}">{{ page }}</a>
                    </li>
                {% endif %}
            {% endfor %}

            <!-- Next page section -->
            {% if pages.has_next %}
                {% if 'title' in querystring %}
                    {% if 'page' in querystring %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring|slice:":-7" }}&page={{ pages.next_page_number }}">Next</a>
                        </li>
                    {% else %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring }}&page={{ pages.next_page_number }}">Next</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="paginator {% if pages.number == page %}active{% endif %}">
                        <a href="?page={{ pages.next_page_number }}">Next</a>
                    </li>
                {% endif %}
            {% endif %}

        </ul>
    {% endwith %}

</div>

以下は念のためのビューです。

app/views.py

def index(request):
    condo_list = Condo.objects.all().order_by('-timestamp_created')
    condo_filter = CondoFilter(request.GET, queryset=condo_list)

    paginator = Paginator(condo_filter.qs, MAX_CONDOS_PER_PAGE)
    page = request.GET.get('page')

    try:
        condos = paginator.page(page)
    except PageNotAnInteger:
        condos = paginator.page(1)
    except EmptyPage:
        condos = paginator.page(paginator.num_pages)


    return render(request, 'app/index.html', {
        'title': 'Home',
        'condos': condos,
        'page': page,
        'condo_filter': condo_filter,
    })

これが実際の例です:

2
DonExo

回答を追加するために、私はDjango-filtersとPaginatorとともにhtmlテーブルでもそれを行いました。以下は私のビューとテンプレートファイルです。テンプレートタグは、ページネーションURLに正しいパラメーターを確実に渡すために必要です。

search_view.py

from Django.shortcuts import render
from app.models.filters_model import ApiStatusFilter
from app.models.api_status import ApiStatus
from Django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from datetime import datetime, timedelta

def status(request):
    all_entries_ordered = ApiStatus.objects.values().order_by('-created_at')[:200]

    for dictionarys in all_entries_ordered:
        dictionarys

    apistatus_list = ApiStatus.objects.values().order_by('-created_at')
    apistatus_filter = ApiStatusFilter(request.GET, queryset=apistatus_list)

    paginator = Paginator(apistatus_filter.qs, 10)
    page = request.GET.get('page')
    try:
        dataqs = paginator.page(page)
    except PageNotAnInteger:
        dataqs = paginator.page(1)
    except EmptyPage:
        dataqs = paginator.page(paginator.num_pages)

    return render(request, 'status_page_template.html', {'dictionarys': dictionarys, 'apistatus_filter': apistatus_filter, 'dataqs': dataqs, 'allobjects': apistatus_list})

status_template.html

{% load static %}
{% load my_templatetags %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="stylesheet" type="text/css" href="{% static 'css/table_styling.css' %}">
        <meta charset="UTF-8">
        <title>TEST</title>
    </head>

    <body>
         <table>
            <thead>
                <tr>
                    {% for keys in dictionarys.keys %} 
                        <th>{{ keys }}</th>
                    {% endfor %}
                </tr>
            </thead>
                <form method="get">
                    {{ apistatus_filter.form.as_p }}
                    <button type="submit">Search</button>
                        {% for user in dataqs.object_list %}
                        <tr>
                            <td>{{ user.id }}</td>
                            <td>{{ user.date_time }}</td>
                            <td>{{ user.log }}</td>
                        </tr>
                        {% endfor %}
                </form>
            </tbody>
        </table>

        <div class="pagination">
            <span>
                {% if dataqs.has_previous %}
                    <a href="?{% query_transform request page=1 %}">&laquo; first</a>
                    <a href="?{% query_transform request page=dataqs.previous_page_number %}">previous</a>
                {% endif %}

                <span class="current">
                    Page {{ dataqs.number }} of {{ dataqs.paginator.num_pages }}.
                </span>

                {% if dataqs.has_next %}
                    <a href="?{% query_transform request page=dataqs.next_page_number %}">next</a>
                    <a href="?{% query_transform request page=dataqs.paginator.num_pages %}">last &raquo;</a>
                {% endif %}
            </span>
        </div> 
    </body>
</html>

my_templatetags.py

from Django import template

register = template.Library()

@register.simple_tag
def query_transform(request, **kwargs):
    updated = request.GET.copy()
    for k, v in kwargs.items():
        if v is not None:
            updated[k] = v
        else:
            updated.pop(k, 0)

    return updated.urlencode()
1
Elia Ahadi

私が理解したように、あなたの目標はあなたのフィルタリングされたクエリセットをページ分割することです。その場合、PublicationFilterオブジェクトの「qs」プロパティをPaginatorコンストラクターに渡すことができます。

def search(request):
    qs = local_url.objects.filter(global_url__id=1).all()
    url_filter = PublicationFilter(request.GET, queryset=qs)
    paginator = Paginator(url_filter.qs, 25)
    page = request.GET.get('page')
    try:
        pub = paginator.page(page)
    except PageNotAnInteger:
        pub = paginator.page(1)
    except EmptyPage:
        pub = paginator.page(paginator.num_pages)
    url_filter = PublicationFilter(request.GET, queryset=qs)
    return render(request, 'ingester/search_list.html', {'publication':pub})

rl_filter.qsフィルターされたクエリセットが含まれています
rl_filter.querysetフィルタリングされていないクエリセットが含まれています

1
Alexey