乐趣区

关于django:基于Django的医案校对网站设计与实现2

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 治理后盾增加自定义信息及定制化页面

退出移动版