简体   繁体   中英

Paginator for inline models in django admin

I have this simple django model consisting of an sensor and values for the specific sensor. The number of values per Pyranometer is high (>30k). Is it somehow possible to paginate PyranometerValues by a specific day or generell apply a paginator to the admin inline view?

class Pyranometer(models.Model):
     name = models.CharField(max_length=75)                                                                             

class PyranometerValues(models.Model):                                                                                 
    timestamp = models.DateTimeField()
    value = models.DecimalField(max_digits=10,decimal_places=6)                                                        
    sensor = models.ForeignKey('Pyranometer')      

If anyone requires this, I found this nice (though described as "quite hacky") implementation of a pagination TabularInline subclass in this comment of a django-suit issue.

For Django 1.6 it requires a template change and subclassing this PaginationInline class:

from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
from django.core.paginator import EmptyPage, InvalidPage, Paginator

class InlineChangeList(object):
    can_show_all = True
    multi_page = True
    get_query_string = ChangeList.__dict__['get_query_string']

    def __init__(self, request, page_num, paginator):
        self.show_all = 'all' in request.GET
        self.page_num = page_num
        self.paginator = paginator
        self.result_count = paginator.count
        self.params = dict(request.GET.items())


class PaginationInline(admin.TabularInline):
    template = 'admin/edit_inline/tabular_paginated.html'
    per_page = 20

    def get_formset(self, request, obj=None, **kwargs):
        formset_class = super(PaginationInline, self).get_formset(
            request, obj, **kwargs)
        class PaginationFormSet(formset_class):
            def __init__(self, *args, **kwargs):
                super(PaginationFormSet, self).__init__(*args, **kwargs)

                qs = self.queryset
                paginator = Paginator(qs, self.per_page)
                try:
                    page_num = int(request.GET.get('p', '0'))
                except ValueError:
                    page_num = 0

                try:
                    page = paginator.page(page_num + 1)
                except (EmptyPage, InvalidPage):
                    page = paginator.page(paginator.num_pages)

                self.cl = InlineChangeList(request, page_num, paginator)
                self.paginator = paginator

                if self.cl.show_all:
                    self._queryset = qs
                else:
                    self._queryset = page.object_list

        PaginationFormSet.per_page = self.per_page
        return PaginationFormSet

For any version of Django , follow these steps:

  1. Visit this file: python3.7/site-packages/django/contrib/admin/templates/admin/edit_inline/tabular.html make a copy of it in your app/templates/admin/edit_inline/anyname.html

between </table> and </fieldset> tag add in anyname.html :

   <style>
    .dark {
      /*background-color: #417690;*/
      background-color: #FFFFFF;
      border: none;
      color: #666;
      padding: 5px 10px;
      text-align: center;
      text-decoration: none;
      display: inline-block;
      font-size: 12px;
      margin: 4px 2px;
      cursor: pointer;
    }
    .light {
      background-color: #008CBA;
      border: none;
      color: white;
      padding: 5px 10px;
      text-align: center;
      text-decoration: none;
      display: inline-block;
      font-size: 12px;
      margin: 4px 2px;
      cursor: pointer;
    }

  </style>
   <div>
   {% with inline_admin_formset.formset.page as page_obj %}
    <p class="paginator">
      {% if page_obj.previous_page_number > 1 %}
        <a href="?page={{ page_obj.previous_page_number|add:'-1' }}">{% trans 'previous' %}</a>
      {% endif %}

      {% if page_obj.number|add:"-5" > 0 %}
        <a href="?page=0">1</a>
      {% endif %}

      {% if page_obj.number|add:"-5" > 1 %}
        <span>&hellip;</span>
      {% endif %}

      {% for page_num in page_obj.paginator.page_range %}
        {% if page_obj.number == page_num %}
          <span class="dark">{{ page_num|add:"-1" }}</span>
        {% else %}
          {% if page_num > page_obj.number|add:"-5" and page_num < page_obj.number|add:"5" %}
            <a class="light" style="color:white" href="?page={{ page_num|add:'-1' }}">{{ page_num|add:"-1" }}</a>
          {% endif %}
        {% endif %}
      {% endfor %}

      {% if page_obj.number|add:"5" < page_obj.paginator.num_pages %}
        <span>&hellip;</span>
      {% endif %}

      {% if page_obj.number|add:"4" < page_obj.paginator.num_pages %}
        <a href="?page={{ page_obj.paginator.num_pages }}">{{ page_obj.paginator.num_pages }}</a>
      {% endif %}

      {% if page_obj.next_page_number < page_obj.paginator.num_pages|add:'1' %}
        <a href="?page={{ page_obj.next_page_number|add:'-1' }}">{% trans 'next' %}</a>
      {% endif %}
      <span class='dark'>{{ page_obj.paginator.count }} Queries</span>
    </p>
  {% endwith %}
  </div> 

2.Go to your admin.py file:

from django.contrib.admin.views.main import ChangeList
from django.core.paginator import EmptyPage, InvalidPage, Paginator

class InlineChangeList(object):
    can_show_all = True
    multi_page = True
    get_query_string = ChangeList.__dict__['get_query_string']

    def __init__(self, request, page_num, paginator):
        self.show_all = 'all' in request.GET
        self.page_num = page_num
        self.paginator = paginator
        self.result_count = paginator.count
        self.params = dict(request.GET.items())


class MyInline(admin.TabularInline):
    per_page = 10
    template = 'admin/edit_inline/anyname.html'
    model = Mymodel
    extra = 0
    can_delete = False

    def get_formset(self, request, obj=None, **kwargs):
        formset_class = super(MyInline, self).get_formset(
            request, obj, **kwargs)
        class PaginationFormSet(formset_class):
            def __init__(self, *args, **kwargs):
                super(PaginationFormSet, self).__init__(*args, **kwargs)

                qs = self.queryset
                paginator = Paginator(qs, self.per_page)
                try:
                    page_num = int(request.GET.get('page', ['0'])[0])
                except ValueError:
                    page_num = 0

                try:
                    page = paginator.page(page_num + 1)
                except (EmptyPage, InvalidPage):
                    page = paginator.page(paginator.num_pages)

                self.page = page
                self.cl = InlineChangeList(request, page_num, paginator)
                self.paginator = paginator

                if self.cl.show_all:
                    self._queryset = qs
                else:
                    self._queryset = page.object_list

        PaginationFormSet.per_page = self.per_page
        return PaginationFormSet

Have you checked raw_id_fields attribute? I think you might find it useful.

As django-admin is mainly a matter of templates (only needed to redefine templates to i18n some django-admin-tools parts), I have an idea.

The are pagination modules for Django, like linaro-django-pagination or endless-pagination, which provide template tags to paginate anything given it is iterable.

If you could find the template in charge of displaying inline models, you could copy it in your project, then try adding a {% load pagination_tags %} to it and paginate the inlines.

I have not tested it nor thought it very thoroughly but except for validation, I don't see how it could fail. Just test and tell us.

Well, maybe dynamically generated filters would help:

https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter

Also, the admin has a nice GET-type query as in:

localhost:8000/admin/pyranometervalues/?value=10.0

You could specify the date as:

admin/pyranometervalues/?timestamp_ year=2011&timestamp _month=10&timestamp__day=13

and so on... Unfortunately I don't know a shorter way to make this query in admin. Any ideas? :)

EDIT: this is only for narrowing your query, doesn't have anything to do with pagination;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM