Bagaimana cara saya menggunakan pagination dengan ListViews generik berbasis kelas Django?

183

Bagaimana saya menggunakan pagination dengan Django 1.3?

Dokumentasi tidak begitu jelas tentang ini.

  • Apa yang terjadi pada saya views.py?

  • Apa yang terjadi pada templat saya?

  • Apa yang terjadi pada file URLconf saya?

Gat
sumber

Jawaban:

338

Saya pikir Anda meminta informasi tentang menggunakan pagination dengan tampilan berbasis kelas baru karena, dengan tampilan berbasis fungsi tradisional, mudah ditemukan. Saya menemukan bahwa hanya dengan mengatur paginate_byvariabel sudah cukup untuk mengaktifkan pagination. Lihat di tampilan umum berbasis Kelas .

Misalnya, di views.py:

import models
from django.views.generic import ListView

class CarListView(ListView):
    model = models.Car      # shorthand for setting queryset = models.Car.objects.all()
    template_name = 'app/car_list.html'  # optional (the default is app_name/modelNameInLowerCase_list.html; which will look into your templates folder for that path and file)
    context_object_name = "car_list"    #default is object_list as well as model's_verbose_name_list and/or model's_verbose_name_plural_list, if defined in the model's inner Meta class
    paginate_by = 10  #and that's it !!

Dalam template Anda ( car_list.html), Anda dapat menyertakan bagian pagination seperti ini (kami memiliki beberapa variabel konteks yang tersedia: is_paginated, page_obj, dan paginator).

{# .... **Normal content list, maybe a table** .... #}
{% if car_list %}
    <table id="cars">
        {% for car in car_list %}
            <tr>
                <td>{{ car.model }}</td>
                <td>{{ car.year }}</td>
                <td><a href="/car/{{ car.id }}/" class="see_detail">detail</a></td>
            </tr>
        {% endfor %}
    </table>
    {# .... **Now the pagination section** .... #}
    {% if is_paginated %}
        <div class="pagination">
            <span class="page-links">
                {% if page_obj.has_previous %}
                    <a href="/cars?page={{ page_obj.previous_page_number }}">previous</a>
                {% endif %}
                <span class="page-current">
                    Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
                </span>
                {% if page_obj.has_next %}
                    <a href="/cars?page={{ page_obj.next_page_number }}">next</a>
                {% endif %}
            </span>
        </div>
    {% endif %}
{% else %}
    <h3>My Cars</h3>
    <p>No cars found!!! :(</p>
{% endif %}
{# .... **More content, footer, etc.** .... #}

Halaman yang akan ditampilkan ditunjukkan oleh parameter GET, cukup menambahkan ?page=n, ke URL.

ervin
sumber
1
Itu ok, tapi bagaimana Anda mengikat template juga melihat objek "car_list"?
gath
28
FYI Anda juga dapat melakukan ini secara langsung di urls.py:url(r'^cars/$ ', ListView.as_view (model = Mobil, paginate_by = 10)),
shawnwall
pelajaran yang saya pelajari: untuk menemukan metode, buka semua kelas leluhur di tab baru, dan CTRL + F pergi kata kuncinya. jadi dari docs.djangoproject.com/en/dev/ref/class-based-views/… , yang kita tahu ada dari tutorial dasar, buka semua tautan Leluhur dan cari "pagi"
Ciro Santilli 郝海东 冠状 病 六四 事件法轮功
2
Saya telah melakukan ini, tetapi masalah yang saya temukan adalah ketika saya melakukan pemrosesan ekstra pada objek dalam queryset, itu berlaku untuk semua hasil dalam database. Jadi untuk kueri yang mengembalikan 100 objek, tetapi hanya menampilkan sepuluh objek per halaman, pemrosesan ekstra akan dilakukan pada 100 objek.
wobbily_col
32
Saya tidak suka url hardcoded yang dapat Anda ganti dengan: <a href="?page={{ page_obj.previous_page_number }}"> sebelumnya </a>
dalore
42

anggap, saya memiliki kelas di app / models.py bernama FileExam(models.Model):

app / models.py

class FileExam(models.Model):
    myfile = models.FileField(upload_to='documents/%Y/%m/%d')
    date = models.DateTimeField(auto_now_add=True, blank=True)
    teacher_name = models.CharField(max_length=30)
    status = models.BooleanField(blank=True, default=False)

app / views.py

from app.models import FileExam
from django.core.paginator import Paginator
from django.core.paginator import EmptyPage
from django.core.paginator import PageNotAnInteger

class FileExamListView(ListView):
    model = FileExam
    template_name = "app/exam_list.html"
    paginate_by = 10
    
    def get_context_data(self, **kwargs):
        context = super(FileExamListView, self).get_context_data(**kwargs) 
        list_exam = FileExam.objects.all()
        paginator = Paginator(list_exam, self.paginate_by)

        page = self.request.GET.get('page')

        try:
            file_exams = paginator.page(page)
        except PageNotAnInteger:
            file_exams = paginator.page(1)
        except EmptyPage:
            file_exams = paginator.page(paginator.num_pages)
            
        context['list_exams'] = file_exams
        return context

Hanya sedikit perubahan dalam get_context_datadan menambahkan kode halaman dari dokumentasi Django di sini

app / templates / app / exam_list.html

daftar konten normal

<table id="exam">
  {% for exam in list_exams %}
  <tr>
    <td>{{ exam.myfile }}</td>
    <td>{{ exam.date }}</td>
    <td>.....</td>
  </tr>
  {% endfor %}
</table>

bagian paginate

{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
    <li>
        <span><a href="?page={{ page_obj.previous_page_number }}">Previous</a></span>
    </li>
{% endif %}
    <li class="">
        <span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>
    </li>
{% if page_obj.has_next %}
    <li>
        <span><a href="?page={{ page_obj.next_page_number }}">Next</a></span>
    </li>
{% endif %}
</ul>
{% else %}
    <h3>Your File Exam</h3>
    <p>File not yet available</p>
{% endif %}

app / urls.py

urlpatterns = [
url(
    r'^$', views.FileExamListView.as_view(), name='file-exam-view'),
), 
... ]
Yanwar Sky
sumber
1
Ini tidak terlihat benar: context = super(SoalListView, self).... Apakah maksud Anda: context = super(FileExamListView, self)...?
cezar
Ya benar! Jawaban ini telah diedit oleh Mr. Yacin. Terima kasih, Pak Yacin.
Yanwar Sky
1

Kami memiliki 2 metode untuk melakukan ini.

Yang pertama sederhana dan hanya mengatur bidang kelas paginate_by . Tidak ada yang perlu kita lakukanget_context_data metode.

Metode kedua agak rumit, tetapi kita bisa lebih memahami tentang pagination dan menyesuaikan pagination yang kompleks atau beberapa pagination. Mari kita lihat.

Itu bisa dilakukan dalam tiga langkah.

1.Override get_context_datametode AndaView .

Lulus page_keysdan pagesagar kami dapat mengulangi daftar dan menghindari pengkodean keras.

def get_context_data(self, *, object_list=None, **kwargs):
    context = super().get_context_data()
    df = pd.DataFrame(list(self.model.objects.all().values()))
    ipc = df.groupby('ip')['ip'].count().sort_values(ascending=False)
    urlc = df.groupby('url')['url'].count().sort_values(ascending=False).to_dict()

    ipc = tuple(ipc.to_dict().items())
    urlc = tuple(urlc.items())

    pages = []
    page_keys = ['page1', 'page2']
    for obj, name in zip([urlc, ipc], page_keys):
        paginator = Paginator(obj, 20)
        page = self.request.GET.get(name)
        page_ipc = obj
        try:
            page_ipc = paginator.page(page)
        except PageNotAnInteger:
            page_ipc = paginator.page(1)
        except EmptyPage:
            page_ipc = paginator.page(paginator.num_pages)
        pages.append(page_ipc)

    context['data'] = zip(pages, page_keys)
    return context

2. Sesuaikan sub Anda template .

Kami mendefinisikan beberapa variabel sehingga kami dapat beralih melalui daftar pagination.

pagination.html

    {% if is_paginated %}
        <ul class="pagination">
        {% if page_obj.has_previous %}
            <li>
            <span><a href="?{{ pname }}={{ page_obj.previous_page_number }}">Previous</a></span>
            </li>
        {% endif %}
        <li class="">
            <span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>
        </li>
        {% if page_obj.has_next %}
            <li>
            <span><a href="?{{ pname }}={{ page_obj.next_page_number }}">Next</a></span>
            </li>
        {% endif %}
        </ul>
    {% else %}
        <h3>Your File Exam</h3>
        <p>File not yet available</p>
    {% endif %}

3. menyesuaikan luar template.

index.html

{% for foo,name in data %}
    <div class="col-md-3 table-responsive">

            {% for k,v in foo %}
                <tr>
                    <th>{{ forloop.counter }}</th>
                    <td>{{ k }}</td>
                    <td>{{ v }}</td>
                </tr>
            {% endfor %}

        {% include 'pagination.html' with pname=name  page_obj=foo %}
    </div>
{% endfor %}
W.Perrin
sumber