Comment utiliser la pagination avec les ListViews génériques basées sur les classes Django?

183

Comment utiliser la pagination avec Django 1.3?

La documentation n'est pas très claire à ce sujet.

  • Qu'est-ce qui va à mon views.py?

  • Qu'est-ce qui va à mon modèle?

  • Que contient mon fichier URLconf?

gath
la source

Réponses:

338

Je pense que vous demandez des informations sur l'utilisation de la pagination avec les nouvelles vues basées sur les classes car, avec les vues basées sur les fonctions traditionnelles, elles sont faciles à trouver. J'ai trouvé que le simple réglage de la paginate_byvariable suffit à activer la pagination. Voir dans les vues génériques basées sur les classes .

Par exemple, dans votre 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 !!

Dans votre modèle ( car_list.html), vous pouvez inclure une section de pagination comme celui - ci (nous avons quelques variables de contexte disponibles: is_paginated, page_objet 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.** .... #}

La page à afficher est indiquée par un paramètre GET, simplement en ajoutant ?page=n, à l'URL.

ervin
la source
1
C'est ok, mais comment lier le modèle aussi voir l'objet "car_list"?
gath
28
Pour info, vous pouvez également le faire directement dans urls.py:url(r'^cars/$ ', ListView.as_view (model = Car, paginate_by = 10)),
shawnwall
leçon que j'ai apprise: pour trouver une méthode, ouvrez toutes les classes ancêtres dans de nouveaux onglets, et CTRL + F éloigne le mot clé. donc à partir de docs.djangoproject.com/en/dev/ref/class-based-views/... , dont nous savons qu'il existe dans le didacticiel de base, ouvrez tous les liens Ancestors et recherchez "pagi"
Ciro Santilli 郝海东 冠状 病 六四 事件法轮功
2
J'ai fait cela, mais le problème que je trouve, c'est que lorsque je fais un traitement supplémentaire sur des objets dans le jeu de requêtes, cela les applique à tous les résultats de la base de données. Ainsi, pour une requête qui renvoie 100 objets, mais ne montre que dix objets par page, le traitement supplémentaire sera effectué sur 100 objets.
wobbily_col
32
Je n'aime pas les URL codées en dur par lesquelles vous pouvez le remplacer: <a href="?page={{ page_obj.previous_page_number }}"> précédent </a>
dalore
42

Supposons que j'ai une classe dans app / models.py nommée 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

Seulement un petit changement dans le get_context_datacode de pagination et ajouté de la documentation de django ici

app / templates / app / exam_list.html

liste de contenu normal

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

section paginer

{% 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'),
), 
... ]
Ciel de Yanwar
la source
1
Cela ne semble pas correcte: context = super(SoalListView, self).... Vouliez-vous dire context = super(FileExamListView, self)...:?
cezar le
Oui, c'est vrai! Cette réponse a été éditée par M. Yacin. Merci, monsieur Yacin.
Yanwar Sky le
1

Nous avons 2 méthodes pour le faire.

Le premier est simple et définit simplement le champ de classe paginate_by. Nous n'avons rien à voir avec la get_context_dataméthode.

La deuxième méthode est un peu compliquée mais nous pouvons mieux comprendre la pagination et personnaliser une pagination complexe ou plusieurs paginations. Voyons ça.

Cela peut être fait en trois étapes.

1.Override get_context_dataméthode de votre View.

Passez page_keyset pagespour que nous puissions itérer les listes et éviter le codage en dur.

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. Personnalisez votre sous-marin template.

Nous définissons certaines variables afin de pouvoir parcourir la liste de 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. personnaliser l'extérieur 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
la source