1 后盾治理批改 – 减少栏目
在左侧减少自定义的栏目是网站我的项目的常见需要。因为 Django 后盾栏目是依据 Model 主动生成的,所以能够在 model.py 中定义一个 model,而后在 admin.py 中定义对应的类,并注册下来,这样就会在左侧主动生成一个栏目。
model.py 中增加如下类:
class CheckAll(models.Model):
class Meta:
app_label = 'case_check'
verbose_name = '校对批量调配(按起源)'
verbose_name_plural = '校对批量调配(按起源)'
在 admin.py 中增加如下的类(此类的性能还没有实现,前期再实现):
@admin.register(CheckAll)
class CheckAllAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_content=None):
return request
这样,左侧就有了“校对批量调配(按起源)”的栏目。
2 后盾治理批改 –change_list 页面批改
需要:须要在 admin 后盾的 list 页面上减少链接(或者是按钮)“显示已校对”、“显示未校对”、“显示所有”,点击之后 list 页面依照对应要求显示内容。
2.1 用 action 的办法实现 – 失败
因为对 admin 后盾不相熟,开始在 action 外面增加一个动作,想通过 action 实现此性能。后果发现,在点击 go 之后,尽管会去执行 action 对应的函数外面的代码,然而还是返回到以后的 model list 页面执行所有记录的查问。所以此路不通。
增加 action 办法,在 admin.py 文件对应的 XXModelAdmin 类中增加如下代码:
# 批改 action 内容
actions = ['show_all']
def show_all(self, request, queryset):
pass
show_all.short_description = "显示已校对"
show_all.acts_on_all = True
action 还有一个问题,就是在执行 go 操作之前必须抉择至多一条记录进行操作,去掉此限度,能够在 changelist_view()中退出如下代码实现:
# 移除 action 必须抉择一个记录的限度
def changelist_view(self, request, extra_context=None):
try:
action = self.get_actions(request)[request.POST['action']][0]
action_acts_on_all = action.acts_on_all
except (KeyError, AttributeError):
action_acts_on_all = False
if action_acts_on_all:
post = request.POST.copy()
post.setlist(admin.helpers.ACTION_CHECKBOX_NAME,
self.model.objects.values_list('id', flat=True))
request.POST = post
return super(OriginCaseAdmin, self).changelist_view(request, extra_context)
2.2 在 change_list 页面上增加链接
为了可能在后盾列表页面上进行批改,必须批改对应的模板文件,admin 后盾的模板文件没有放在我的项目外面,而是放在 Django 的源码中,其体门路是在你我的项目的虚构门路下:venv4network\Lib\site-packages\django\contrib\admin\templates\admin
Django 的 admin 后盾列表页面对应的是 change_list.html 页面,须要将此文件复制到模板文件夹下。在我的项目的 templates 目录下,新建 admin 文件夹,在新建项目名称的文件夹(我这里是 case_check),在新建你对应的 Model 类名称的文件夹(我这里是 origincase),而后把 change_list.html 文件复制在此文件夹中。
关上 change_list.html,在对应地位增加一个 div,把咱们对应的链接增加下来,上面截取局部代码:
{% block result_list %}
{% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %}
<div><a href="?mode=show_all"> 显示所有 </a> <a href="?mode=show_check"> 仅显示已校对 </a> <a href="?mode=show_nocheck"> 仅显示未校对 </a></div>
{% result_list cl %}
{% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %}
{% endblock %}
2.3 用 GET 传递参数,在 get_queryset()办法中进行判断 – 失败
想到 get_queryset()办法是返回数据集的最终办法,如果在这个函数外面做一个条件判断,那么应该能够实现。然而,如何触发条件呢?以 action 的形式曾经不行,那么能够通过链接的形式,在 GET 上传递一个参数,依据这个参数触发条件。但还是失败了。
这个我的链接 http://127.0.0.1:8000/admin/c…,通过 request.GET 取得 mode 对应的 show_all 这个值。然而,每次点击完这个链接之后,都会跳转到一个带谬误的链接地址上:
http://127.0.0.1:8000/admin/c…
为了找到失败起因,查看了 Django 的 changelist_view()办法的源码,终于发现了问题所在。上面是一段源码,外面对 GET 参数进行了查看,把不非法的参数进行了重定向。当然,这是 Django 对于防注入攻打的一个很好的性能,却是把我整晕了好一阵。
try:
cl = self.get_changelist_instance(request)
except IncorrectLookupParameters:
# Wacky lookup parameters were given, so redirect to the main
# changelist page, without parameters, and pass an 'invalid=1'
# parameter via the query string. If wacky parameters were given
# and the 'invalid=1' parameter was already in the query string,
# something is screwed up with the database, so display an error
# page.
if ERROR_FLAG in request.GET:
return SimpleTemplateResponse('admin/invalid_setup.html', {'title': _('Database error'),
})
return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
2.3 传递 GET 参数,写入 session,在在 get_queryset()办法中进行判断 – 胜利
2.2 中,每一次传递的参数都被主动重定向了,我不可能去改 Django 的源码啊,也不举荐这么去做。怎么办呢?
第一,须要对 GET 传递的参数进行获取和判断,并对这个判断后果进行状态放弃;
第二,防止触发重定向;
第三,在 get_queryset()办法对状态进行判断,以返回对应的数据集。
所以第一步的状态必须在第三步中可能应用,而 request 曾经不适宜作为参数传递了,所以想到用 session 来放弃这个参数。把 GET 中获取的参数放弃在 session 中,最初利用 session 中的参数,在 get_queryset()中进行判断。同时,为了防止触发重定向,咱们须要批改 request。
上面别离来实现:
第一、第二步:获取 GET 参数,这个须要在 admin 的业务逻辑中实现,这个对应在 changelist_view()办法中实现。获取到 show_all 之后,写入到 session,而后必须把 GET 外面内容删除,删除之后就不会触发重定向;否则 super(OriginCaseAdmin, self).changelist_view(request, extra_context)之后,还是会重定向页面。
def changelist_view(self, request, extra_context=None):
if request.method == "GET" and (mode := request.GET.get('mode')) == "show_all":
request.session["mode"] = "show_all"
get = request.GET.copy()
del get["mode"]
request.GET = get
return super(OriginCaseAdmin, self).changelist_view(request, extra_context)
第三步,在 get_queryset()办法中对 session 值进行判断,过滤数据集对应的值。
def get_queryset(self, request):
qs = super(OriginCaseAdmin, self).get_queryset(request)
if request.user.is_superuser:
if request.session.get("mode") == "show_all":
request.session["mode"] = None
if request.session.get("mode") == "show_check":
request.session["mode"] = None
return qs.filter(check_flag="是")
if request.session.get("mode") == "show_nocheck":
request.session["mode"] = None
return qs.filter(check_flag="")
return qs
else:
if request.session.get("mode") == "show_all":
request.session["mode"] = None
if request.session.get("mode") == "show_check":
request.session["mode"] = None
return qs.filter(check_flag="是").filter(user = request.user)
if request.session.get("mode") == "show_nocheck":
request.session["mode"] = None
return qs.filter(check_flag="").filter(user = request.user)
return qs.filter(user=request.user)
总感觉实现的怪怪的,代码也简短,但好歹实现了性能。因为对 Django 不相熟,目前想到的是这种办法,兴许还有更好的、更不便的办法来实现。
参考文献
几个比拟好的参考文献保留一下:
3.Python Django 之 GET 申请和 POST 申请及响应解决
Django 定制 Admin 页面(展现页面和编辑页面)
这篇通知定义列表行中的自定义按钮或链接:对于在 django 框架中在 admin 页面下增加自定义按钮并实现性能
如何在 Django admin 中创立自定义按钮,它会创立许多对象?
Django Admin 治理后盾增加自定义信息及定制化页面