¿Cómo uso la paginación con ListViews genéricos basados ​​en la clase Django?

183

¿Cómo uso la paginación con Django 1.3?

La documentación no es muy clara al respecto.

  • ¿Qué le pasa a mi views.py?

  • ¿Qué va a mi plantilla?

  • ¿Qué va a mi archivo URLconf?

gath
fuente

Respuestas:

338

Creo que solicita información sobre el uso de la paginación con las nuevas vistas basadas en clases, ya que, con vistas tradicionales basadas en funciones, es fácil de encontrar. Descubrí que solo configurando la paginate_byvariable es suficiente para activar la paginación. Ver en vistas genéricas basadas en clases .

Por ejemplo, en tu 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 !!

En su plantilla ( car_list.html), puede incluir una sección de paginación como esto (tenemos algunas variables de contexto disponibles: is_paginated, page_obj, y 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 página para mostrar se indica mediante un parámetro GET, simplemente agregando ?page=n, a la URL.

ervin
fuente
1
Está bien, pero ¿cómo se vincula la plantilla para ver también el objeto "car_list"?
Gath
28
Para su información, también puede hacerlo directamente en urls.py:url(r'^cars/$ ', ListView.as_view (model = Car, paginate_by = 10)),
shawnwall
Lección que aprendí: para encontrar un método, abra todas las clases de antepasados ​​en nuevas pestañas y CTRL + F aleje la palabra clave. así que de docs.djangoproject.com/en/dev/ref/class-based-views/… , que sabemos que existe del tutorial básico, abra todos los enlaces de Ancestros y busque "pagi"
Ciro Santilli 郝海东 冠状 病 六四 事件法轮功
2
He estado haciendo esto, pero el problema que encuentro es que cuando realizo un procesamiento adicional en los objetos del conjunto de consultas, los aplica a todos los resultados de la base de datos. Entonces, para una consulta que devuelve 100 objetos, pero muestra solo diez objetos por página, el procesamiento adicional se realizará en 100 objetos.
wobbily_col
32
No me gustan las URL codificadas con las que puede reemplazarlo: <a href="?page={{ page_obj.previous_page_number }}"> previous </a>
dalore
42

supongo que tengo una clase en app / models.py llamada 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

Solo un pequeño cambio en el get_context_datacódigo de paginación agregado de la documentación de django aquí

app / templates / app / exam_list.html

lista de contenido normal

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

sección paginada

{% 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
fuente
1
Esto no se ve bien: context = super(SoalListView, self).... ¿Quiso decir context = super(FileExamListView, self)...:?
cezar
¡Si claro! Esta respuesta ha sido editada por el Sr. Yacin. Gracias señor Yacin.
Yanwar Sky
1

Tenemos 2 métodos para hacer esto.

El primero es simple y solo establece el campo de clase paginate_by. Nada tiene que ver con el get_context_datamétodo.

El segundo método es un poco complicado, pero podemos obtener una mayor comprensión acerca de la paginación y personalizar la paginación compleja o varias paginación. Vamos a verlo.

Se puede hacer en tres pasos.

1. get_context_dataMétodo de anulación de su View.

Pase page_keysy pagespara que podamos iterar las listas y evitar la codificación rígida.

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.Personaliza tu sub template.

Definimos algunas variables para que podamos recorrer la lista de paginación.

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. Personalizar exterior 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
fuente