7

私はDjangoでページネーションを使用してListViewsを学び、理解しようと努めてきましたが、概念を理解するのに問題があるようです。それで、いくつかのコードを見せましょう-私のview.pyは次のようになります:

class SearchDisplayListView(ListView):
    model = BlogPosts
    template_name = "searchres_list.html"
    paginate_by = '15'
    context_object_name = "searchres"

    def get_context_data(self, **kwargs):
        context = super(SearchDisplayListView, self).get_context_data(**kwargs)
        q = self.request.GET.get('q')
        q = q.replace(" ","+")
        context['searchq'] = q
        return context

    def get_queryset(self):
        queryset = super(SearchDisplayListView, self).get_queryset()
        # Get the q GET parameter
        q = self.request.GET.get('q')
        q = q.replace(" ","+")
        if q is None:
        # Return the base queryset
        return queryset
        # Return a filtered queryset
       ## do some awesome calculations using "q" i.e send request to search server
       ## get back a list from the search server.. example: range(0,100)
        queryset = range(0,100)
        return queryset

ご覧のとおり、実際にはモデルを使用してクエリセットにデータを入力するのではなく、結果を返す独自の「検索サーバー」から、たとえばこの例のrange(0,100)から入力します。

今、私は私のテンプレートコードで以下を使用しようとしています:

<table class="table table-hover">
<tbody>
{% for i in searchres %}
<tr>
<td><img src="http://placehold.it/140x140" class="img-polaroid"></td>
<td>{{i}}</td>
</tr>
{% endfor %}
</tbody>
</table>

そして私のページネーションは次のようになります:

{% if is_paginated %}
<div class="pagination pagination-centered">
    <ul>
        {% if page_obj.has_previous %}
<li><a href="/search/?q={{searchq}}/page={{ page_obj.previous_page_number }}">Prev</a></li>
        {% endif %}

        {% for i in paginator.page_range %}
            {% if page_obj.has_next %}
<li><a href="/search/?q={{searchq}}/page={{ page_obj.number }}">{{i}}</a></li>
            {% endif %}
        {% endfor %}

        {% if page_obj.has_next %}
<li><a href="/search/?q={{searchq}}/page={{ page_obj.next_page_number }}">Next</a></li>
        {% endif %}

    </ul>
</div>

今、私は次の問題を抱えています:

[1]テンプレートは最初のセット(つまり、0から14)をページ分割しているように見えますが、後続のページで他の値を確認できません。したがって、次のページをクリックすると、次のようになります。

 - http://mydata:8000/search/?q=myquery/page=2

次のページをもう一度クリックすると、次のようになります。

 - http://mydata:8000/search/?q=boots/page=2/page=2

これは明らかに間違っています。生成する方法がわかりません。

 - http://mydata:8000/search/?q=boots/page=3

[2]手動で設定した場合でも:

 - http://mydata:8000/search/?q=boots/page=3

page:3の論理セットではなく、0から14までの値が再び表示されます。

また、これは基本的に、各ページでget_querysetが実行されているように見え、最初の0から14の値を生成することを示しています。これは私が望むものではありません。

ご覧のとおり、私はget_querysetに独自のカスタムデータセットを持っています-DBインタラクションではなく-したがって、このカスタムデータをどのようにページ付けできるかわかりません。

私のかなり長い投稿を読んでくれてありがとう!

4

4 に答える 4

5

クエリパラメータは、 /ではなく&で区切る必要があります

/search/?q={{searchq}}/page={{ page_obj.previous_page_number }}

する必要があります:

/search/?q={{searchq}}&page={{ page_obj.previous_page_number }}

また、URLをハードコーディングする代わりに、次のようなURLリゾルバーを使用することをお勧めします。

{% url 'search' searchq page_obj.previous_page_number %}
于 2013-02-19T16:49:23.043 に答える
2

念のため、コードは次のようになります。

{% if is_paginated %}
    <div class="pagination pagination-centered">
    <ul>
    {% if page_obj.has_previous %}
        <li><a href="/search/?q={{searchq}}&page={{ page_obj.previous_page_number}}">Prev</a></li>
    {% endif %}

    {% if page_obj.has_next %}
       {% for i in paginator.page_range %}
          <li><a href="/search/?q={{searchq}}&page={{ i }}">{{i}}</a></li>
        {% endfor %}
          <li><a href="/search/?q={{searchq}}&page={{ page_obj.next_page_number }}">Next</a></li>
    {% endif %}

</ul>
</div>

2つの変更があります。1。page_obj.numberは実際のページを返すため、増分変数iに置き換えられます。2. forループは、わかりやすくするためにpage_obj.has_next内に移動されています。このようにすると、ページ番号のリンクは、質問者が意図したようにこのページよりも多い場合にのみ表示されます。とにかくそれを表示したい場合:それを移動するだけです。

于 2014-05-21T11:56:42.707 に答える
0

この問題をしばらく調査し、このエントリから始めた後、私は複雑ですが、一般的な再利用可能なソリューションに行き着きました。

OPにはやり過ぎですが、多くの人がページ付けと検索の問題を抱えているようです。これが私の$.02です。

(Djangoの初心者なので、改善すべき点があると確信していますが、検索とページ付けをすばやく組み合わせることができます。「db」または「mdb」については無視してください。これは非常に特殊です。 Djangoデータベースの外部で生のSQLを頻繁に実行する私のアプリ。)

あらすじ:

基本的に、1つの石で2羽の鳥を殺すことができると思いました。フィルタリングされた行セットで作業していた理由は、フォームから検索を実行していたためです。

そして...フォームは、ページネーションURLを再構築するために必要な情報を提供することができます。

したがって、基本的には、通常の検索フォームを作成し、それを適切にサブクラス化されたバージョンのListViewに接続するというシステムになりました。クラスRoleListViewを参照してください。

リストビューのテンプレートも作成する必要がありますが、それを参照すると、@ pssecurity/security_list.htmlでかなり基本的なものであることがわかります。

詳細:

ページネーションに関する賢い点は、クラスKSearchListView(ListView)にあります。これは完全に一般的なもので、必要な数の検索ページで再利用できます。

メソッドget_queryset。ここで、form.doSearchを呼び出すことによってデータベースフィルタリングが実行されます。

実際のページ付けはメソッドget_context_dataにあります。このメソッドは、フォームがあるかどうかをチェックし、フォームが有効かどうかを確認してから、フォームのクリーンアップされたパラメーターを再入力してページ付けURLを操作します。

また、2つの受信URLがあります。1つはフィルタリングされていないリストで、もう1つはフィルタリングされた検索です。両方とも同じListViewにマップされます。

urls

    #Roles aka PSROLEDEFN
    url(r'^roles/search',
        login_required(RoleListView.as_view()),
        name="psroledefn_search"),

    url(r'^roles/$',
        # 'pssecurity.views.psroledefn_list',
        login_required(RoleListView.as_view()),
        name="psroledefn_list"),



        #generic
class KSearchListView(ListView):
    def __str__(self):
        return self.__class__.__name__

    __repr__ = __str__

    form_class = form = None
    di_hardcoded_context = {}

    def setdb(self):
        #specific to my app
        self.db = self.rdb

    def dispatch(self,*args,**kwargs):
        #specific to my app
        if not self.mdb:
            self.mdb = MultiDb.get(self.kwargs["dbr"])
            self.djangodb = self.mdb.djangodb
            self.rdb = self.mdb.rdb
            self.setdb()
        #specific to my app

        return super(KSearchListView, self).dispatch(*args,**kwargs)

    def get_queryset(self,*args,**kwargs):
        # logging.info("%s.get_queryset(%s,%s)" % (self,args,kwargs))

        self.request.get = self.request.GET

        if self.form_class:
            #pagination info
            #do we have a form and are we coming from it?
            if self.request.method == "GET":
                self.form = self.form_class(self.db, self.request.GET)

                if self.form.is_valid():
                    logging.info("form.doSearch")
                    li_c = self.form.doSearch()
                    return li_c
                else:
                    logging.debug("not is_valid branch")
            else:
                self.form = self.form_class(self.mdb.rdb)
        #fetch all rows for the underlying table
        return self.fetch_all()

    def fetch_all(self):
        #specific to my app
        #you would probably use a <model>.objects.all()
        return list(pssys.Pssys.fetch(self.db,self.recname))


    def _override_context_data(self,context):
        pass

    def get_context_data(self,*args,**kwargs):
        # logging.info("%s.get_context_data(%s,%s)" % (self,args,kwargs))

        context = super(KSearchListView, self).get_context_data(**kwargs)
        context['form'] = self.form
        context["dbr"] = self.mdb.rdbname


        #pagination info
        #we are going to put the GET variables right back into the next/prev
        url = ""
        page_obj = context["page_obj"]
        if self.form and self.form.is_valid() and self.form.cleaned_data:

            li = [self.request.path,"?"]

            #driving the url assembly from the form fields and
            #using the cleaned data should be pretty safe
            di = self.form.cleaned_data
            for k in self.form.fields:
                li.append("%s=%s" % (k,di[k]))
                li.append("&")
            # li = li[:-1]
            url = "".join(li)

        #if we didn't come in through a search form
        if not url:
            url = "?"

        #now conditionally add the previous/next as appropriate. 
        #url has either a trailing ? or & at this point
        kpaging_previous_url = kpaging_next_url = ""
        if page_obj.has_previous():
            kpaging_previous_url = context["kpaging_previous_url"] = url + "page=%s" % (page_obj.previous_page_number())
        if page_obj.has_next():
            kpaging_next_url = context["kpaging_next_url"] = url + "page=%s" % (page_obj.next_page_number())

        logging.debug("url:%s" % (url))
        logging.debug("kpaging_previous_url:%s" % (kpaging_previous_url))
        logging.debug("kpaging_next_url:%s" % (kpaging_next_url))

        #pickup anything the subclass has set for the context
        context.update(self.di_hardcoded_context)
        self._override_context_data(context)
        return context


        #what I need to write for every list/search page...

class RoleListView(KSearchListView):

    template_name = "pssecurity/security_list.html" 
    paginate_by = 20
    recname = "PSROLEDEFN"
    form_class = Search_PSROLEDEFN
    di_hardcoded_context = dict(
        title="Search Roles",
        header="Roles",
        templatename_inst="PSROLEDEFN_list",
        url_action='security:psroledefn_search')

#pagination info the forms

        #generic
class SearchForm(forms.Form):
    def __init__(self, db, request=None):
        self.db = db
        li_arg = [request] if request else []

        super(forms.Form, self).__init__(*li_arg)

    def __str__(self):
        return self.__class__.__name__

    __repr__ = __str__


        #what I need to write for every list/search page...
class Search_PSROLEDEFN(SearchForm):
    ROLENAME = forms.CharField(max_length=20, required=False)
    DESCR = forms.CharField(max_length=32, required=False)

    status_custom = ChooseStatusCustomizationField()
    hasUsers = ChooseYesNoDontCareField("has Users?")
    hasPermissions = ChooseYesNoDontCareField("has Permissions?")
    hasPortalReferences = ChooseYesNoDontCareField("has Portal?")

    def doSearch(self):

        ROLENAME = self.cleaned_data["ROLENAME"]
        DESCR = self.cleaned_data["DESCR"].strip()
        status_custom = self.cleaned_data["status_custom"]

        hasPortalReferences = self.cleaned_data["hasPortalReferences"]
        hasPermissions = self.cleaned_data["hasPermissions"]
        hasUsers = self.cleaned_data["hasUsers"]

        #cut out a lot of code specific to my app
        #you would want to do an appropriate
        #<model>.objects.filter()...
        returns <select from my db>




#a typical template, note that isn't even specific to an object
#refer to class RoleListView to see how the template is built.
#the actual details of the fetched objects are left to <templatename_inst>

pssecurity/security_list.html
{% block search %}
<div id="block_search">
<span>{{header}}</span>

<div class="row">
{% if form %}

<div id="search" class="well col-xs-9" >
    <form class= "form-horizontal" action="{% url url_action dbr=dbr %}" method="get">
        {{form.as_table}}
        <input type="submit" value="search">
    </form>
</div>
{% endif %}
{% endblock %}

{%block content %}
<div id = "block_content">
{% for inst in object_list %}
    <div class="row">
        {% include templatename_inst %}
    </div>
{% endfor %}

{% include "websec/kpagination.html" %}

</div>
{%endblock %}

        #generic
kpagination.html
<div class="pagination">
    <span class="step-links" >
        {% if li_inst.has_previous %}
            <a href="?page={{ li_inst.previous_page_number }}">previous</a>
        {% endif %}

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

        {% if li_inst.has_next %}
            <a \href="?page={{ li_inst.next_page_number }}">next</a>
        {% endif %}
    </span>
</div>
于 2014-08-07T21:50:59.320 に答える
0

djangoクラスベースのリストビューで以下のように行うことができます

views.py

try:
    from urllib import urlencode
except ImportError:
    from urllib.parse import urlencode

class MyListView(ListView):
    # ............
    def get_context_data(self, *args, **kwargs):
        context = super(
            GroupSubsListView, self
        ).get_context_data(*args, **kwargs)
        query_params = self.request.GET.copy()
        query_params.pop('page', None)
        context['query_params'] = urlencode(query_params)
        return context

template.html

<!-- pagination -->
{% if is_paginated %}
  <p>showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ page_obj.paginator.count }}</p>
  <div class="text-center">
    <nav>
      <ul class="pagination">
        {% if page_obj.has_previous %}
        <li class="page-item">
          <a class="page-link" href="?page={{ page_obj.previous_page_number }}&{{ query_params }}" aria-label="Previous">
            Previous
          </a>
        </li>
        {% endif %}
        <li class="page-item"><a class="page-link"> Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}. </a></li>
        {% if page_obj.has_next %}
        <li class="page-item">
          <a class="page-link" href="?page={{ page_obj.next_page_number }}&{{ query_params }}" aria-label="Next">
            Next
          </a>
        </li>
        {% endif %}
      </ul>
    </nav>
  </div>
{% endif %}
  <!-- end/ -->
于 2018-02-20T11:59:16.380 に答える