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.Mod开发者_JAVA百科el):
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:
- Visit this file :
python3.7/site-packages/django/contrib/admin/templates/admin/edit_inline/tabular.html
make a copy of it in yourapp/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>…</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>…</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×tamp_month=10×tamp__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 ;)
精彩评论