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>&nbsp;&nbsp;<a href="?mode=show_check"> 仅显示已校对</a>&nbsp;&nbsp;<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 治理后盾增加自定义信息及定制化页面