Django Admin:如何动态设置 list_per_page
Django Admin: How to dynamically set list_per_page
我遇到了 运行 的情况,我正在管理一个项目的代码库,该项目使用站点的 django-admin 部分。 django 管理的所有功能也存在于普通视图中,但由于某种原因,客户更喜欢在管理视图上工作,而不是基于功能的视图......通常,添加下拉列表并调整 pagination/filter 在基于函数的视图中很容易,但我能看到修改它的唯一方法是使用 list_per_page
如何向管理页面添加下拉菜单(最好使用分页按钮),然后如何在服务器端检索结果以根据用户拥有的内容动态更改 list_per_page
值选?将表单添加到模板并在管理工作中检索 POST 吗?
免责声明:
我正在回答我自己的问题,所以我不确定这是最佳实践还是实现此目标的最佳方法。然而,我所有的搜索都得到了 0 个结果,所以我决定分享它以防其他人需要这个功能。如果有人有任何更好的方法来实现这一点,或者知道我在做一些不安全的事情,请告诉我!
我会尝试将查询参数附加到 URL,然后通过服务器端的请求检索该参数以设置 list_per_page
。要添加下拉列表和参数,修改特定管理结果的媒体 class 以包含一些额外的 javascript 应该允许您创建下拉列表并附加查询参数。我们需要从 request.GET
中删除此参数,否则我们将 运行 变成 get_queryset()
内部的问题,因为该参数与模型上的字段不匹配。为此,我们需要覆盖 admin.py
中的 changelist_view()
方法
admin_paginator_dropdown.js
window.addEventListener('load', function() {
(function($) {
// Jquery should be loaded now
// Table paginator has class paginator. We want to append to this
var paginator = $(".paginator");
var list_per_page = $("<select id='list_per_page_selector'><option value=\"50\">50</option><option value=\"100\" selected>100</option><option value=\"150\">150</option><option value=\"200\">200</option><option value=\"250\">250</option></select>")
var url = new URL(window.location);
// Retrieve the current value for updating the selected dropdown on page refresh
var initial_list_per_page = url.searchParams.get("list_per_page")
paginator.append(list_per_page)
if(initial_list_per_page === null) {
// No choice has been made, set dropdown to default value
$("#list_per_page_selector").val("100")
}
else{
// User has a query parameter with a selection. Update the selected accordingly
$("#list_per_page_selector").val(initial_list_per_page)
}
$("#list_per_page_selector").on("change", function(event) {
// Add the list_per_page parameter to the url to be used in admin.py
url.searchParams.set("list_per_page", event.target.value);
//Take us to the new page.
window.location.href = url.href;
});
})(django.jQuery);
});
admin.py
class someModelAdmin(admin.ModelAdmin)
class Media:
js = ("js/admin_paginator_dropdown.js",)
def changelist_view(self, request, extra_context=None):
# Copy the request.GET so we can modify it (no longer immutable querydict)
request.GET = request.GET.copy()
# Pop the custom non-model parameter off the request (Comes out as an array?)
# Force it to int
page_param = int(request.GET.pop('list_per_page', [100])[0])
# Dynamically set the django admin list size based on query parameter.
self.list_per_page = page_param
return super(someModelAdmin, self).changelist_view(request, extra_context)
受到 的启发,我最终得到了这个:
import django.contrib.admin.views.main
class DynPaginationChangeList(django.contrib.admin.views.main.ChangeList):
def __init__(self, request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by):
page_param = request.GET.get('list_per_page', None)
if page_param is not None:
# Override list_per_page if present in URL
# Need to be before super call to be applied on filters
list_per_page = int(page_param)
super(DynPaginationChangeList, self).__init__(request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by)
def get_filters_params(self, params=None):
"""
Return all params except IGNORED_PARAMS and 'list_per_page'
"""
lookup_params = super(DynPaginationChangeList, self).get_filters_params(params)
if 'list_per_page' in lookup_params:
del lookup_params['list_per_page']
return lookup_params
class AdminDynPaginationMixin:
def get_changelist(self, request, **kwargs):
return DynPaginationChangeList
如果您使用原始答案中建议的 javascript 代码,您只需在 AdminClass 中使用此 Mixin 即可。
我个人重写了 pagination.html 模板,如下所示:
{% load admin_list %}
{% load i18n %}
<p class="paginator">
{% if pagination_required %}
{% for i in page_range %}
{% paginator_number cl i %}
{% endfor %}
{% endif %}
{{ cl.result_count }} {% if cl.result_count == 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endif %}
{% if show_all_url %}<a href="{{ show_all_url }}" class="showall">{% translate 'Show all' %}</a>{% endif %}
{% with '5 10 25 50 100 250 500 1000' as list %} — {% translate 'Number of items per page' %}
<select>
{% if cl.list_per_page|slugify not in list.split %}
<option selected>{{ cl.list_per_page }}</option>
{% endif %}
{% for i in list.split %}
<option value="{{ i }}" {% if cl.list_per_page|slugify == i %}selected{% else %}onclick="var p = new URLSearchParams(location.search);p.set('list_per_page', '{{ i }}');window.location.search = p.toString();"{% endif %}>{{ i }}</option>
{% endfor %}
</select>
{% endwith %}
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% translate 'Save' %}">{% endif %}
</p>
我遇到了 运行 的情况,我正在管理一个项目的代码库,该项目使用站点的 django-admin 部分。 django 管理的所有功能也存在于普通视图中,但由于某种原因,客户更喜欢在管理视图上工作,而不是基于功能的视图......通常,添加下拉列表并调整 pagination/filter 在基于函数的视图中很容易,但我能看到修改它的唯一方法是使用 list_per_page
如何向管理页面添加下拉菜单(最好使用分页按钮),然后如何在服务器端检索结果以根据用户拥有的内容动态更改 list_per_page
值选?将表单添加到模板并在管理工作中检索 POST 吗?
免责声明:
我正在回答我自己的问题,所以我不确定这是最佳实践还是实现此目标的最佳方法。然而,我所有的搜索都得到了 0 个结果,所以我决定分享它以防其他人需要这个功能。如果有人有任何更好的方法来实现这一点,或者知道我在做一些不安全的事情,请告诉我!
我会尝试将查询参数附加到 URL,然后通过服务器端的请求检索该参数以设置 list_per_page
。要添加下拉列表和参数,修改特定管理结果的媒体 class 以包含一些额外的 javascript 应该允许您创建下拉列表并附加查询参数。我们需要从 request.GET
中删除此参数,否则我们将 运行 变成 get_queryset()
内部的问题,因为该参数与模型上的字段不匹配。为此,我们需要覆盖 admin.py
changelist_view()
方法
admin_paginator_dropdown.js
window.addEventListener('load', function() {
(function($) {
// Jquery should be loaded now
// Table paginator has class paginator. We want to append to this
var paginator = $(".paginator");
var list_per_page = $("<select id='list_per_page_selector'><option value=\"50\">50</option><option value=\"100\" selected>100</option><option value=\"150\">150</option><option value=\"200\">200</option><option value=\"250\">250</option></select>")
var url = new URL(window.location);
// Retrieve the current value for updating the selected dropdown on page refresh
var initial_list_per_page = url.searchParams.get("list_per_page")
paginator.append(list_per_page)
if(initial_list_per_page === null) {
// No choice has been made, set dropdown to default value
$("#list_per_page_selector").val("100")
}
else{
// User has a query parameter with a selection. Update the selected accordingly
$("#list_per_page_selector").val(initial_list_per_page)
}
$("#list_per_page_selector").on("change", function(event) {
// Add the list_per_page parameter to the url to be used in admin.py
url.searchParams.set("list_per_page", event.target.value);
//Take us to the new page.
window.location.href = url.href;
});
})(django.jQuery);
});
admin.py
class someModelAdmin(admin.ModelAdmin)
class Media:
js = ("js/admin_paginator_dropdown.js",)
def changelist_view(self, request, extra_context=None):
# Copy the request.GET so we can modify it (no longer immutable querydict)
request.GET = request.GET.copy()
# Pop the custom non-model parameter off the request (Comes out as an array?)
# Force it to int
page_param = int(request.GET.pop('list_per_page', [100])[0])
# Dynamically set the django admin list size based on query parameter.
self.list_per_page = page_param
return super(someModelAdmin, self).changelist_view(request, extra_context)
受到
import django.contrib.admin.views.main
class DynPaginationChangeList(django.contrib.admin.views.main.ChangeList):
def __init__(self, request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by):
page_param = request.GET.get('list_per_page', None)
if page_param is not None:
# Override list_per_page if present in URL
# Need to be before super call to be applied on filters
list_per_page = int(page_param)
super(DynPaginationChangeList, self).__init__(request, model, list_display, list_display_links,
list_filter, date_hierarchy, search_fields, list_select_related,
list_per_page, list_max_show_all, list_editable, model_admin, sortable_by)
def get_filters_params(self, params=None):
"""
Return all params except IGNORED_PARAMS and 'list_per_page'
"""
lookup_params = super(DynPaginationChangeList, self).get_filters_params(params)
if 'list_per_page' in lookup_params:
del lookup_params['list_per_page']
return lookup_params
class AdminDynPaginationMixin:
def get_changelist(self, request, **kwargs):
return DynPaginationChangeList
如果您使用原始答案中建议的 javascript 代码,您只需在 AdminClass 中使用此 Mixin 即可。
我个人重写了 pagination.html 模板,如下所示:
{% load admin_list %}
{% load i18n %}
<p class="paginator">
{% if pagination_required %}
{% for i in page_range %}
{% paginator_number cl i %}
{% endfor %}
{% endif %}
{{ cl.result_count }} {% if cl.result_count == 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endif %}
{% if show_all_url %}<a href="{{ show_all_url }}" class="showall">{% translate 'Show all' %}</a>{% endif %}
{% with '5 10 25 50 100 250 500 1000' as list %} — {% translate 'Number of items per page' %}
<select>
{% if cl.list_per_page|slugify not in list.split %}
<option selected>{{ cl.list_per_page }}</option>
{% endif %}
{% for i in list.split %}
<option value="{{ i }}" {% if cl.list_per_page|slugify == i %}selected{% else %}onclick="var p = new URLSearchParams(location.search);p.set('list_per_page', '{{ i }}');window.location.search = p.toString();"{% endif %}>{{ i }}</option>
{% endfor %}
</select>
{% endwith %}
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% translate 'Save' %}">{% endif %}
</p>