Django管理后台:如何添加自定义列表视图?

2 投票
2 回答
5226 浏览
提问于 2025-04-16 09:03

我想在管理后台提供一个自定义的视图,这个视图跟 changelist_view() 很像,但不包含编辑表单的链接。用户可以在列表中选择项目并执行操作,就像在更改列表表单中一样,但他们无法访问编辑表单。

我觉得在 ModelAdmin 类中的结构应该是这样的:

class ProductAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(ProductAdmin, self).get_urls()
        urls += patterns('',
            (r'^selectlist/$', self.selectlist_view)
        )
        return urls

    def selectlist_view(self):
        return render_to_response(...)

返回的视图跟 ModelAdmin.changelist_view() 非常相似。有什么好的方法可以做到这一点,同时保持代码简洁呢?

2 个回答

3

我不太清楚为什么,但就我个人而言,我倾向于重写(或扩展)特定模型的更改列表模板,而不是直接修改ModelAdmin。

编辑:

谢谢,但我需要的自定义功能不是简单重写模板就能实现的。例如,显示不同的查询集等等。

为了显示不同的查询集,你可以重写ModelAdmin.queryset()。

而且用户不应该能够编辑列表中的项目。如果我重写模板,用户就看不到编辑表单的链接,但如果他们能猜到表单的URL,仍然可以通过输入URL来访问和编辑,这就存在安全隐患。

那为什么不直接把这些用户的编辑权限去掉呢?你也可以重写“添加”和“更改”的视图:

class SomeModelAdmin(admin.ModelAdmin):
    ...
    def change_view(self, request, object_id, extra_context=None):
        return render_to_response('forbiden_operation.html', dict(op='edit'))
    def ModelAdmin.add_view(self, request, form_url='', extra_context=None):
        return render_to_response('forbiden_operation.html', dict(op='add'))

这些是“官方”的钩子,不太可能在将来出问题。

同时记住“管理的禅意”:

从本质上讲,Django的管理界面是为单一活动设计的:

可信用户编辑结构化内容。

是的,这非常简单——但这种简单性是基于一系列假设的。Django管理界面的整个理念直接源于这些假设,所以让我们深入探讨一下这句话的潜台词。

“可信用户……”

管理界面是为你,作为开发者,信任的人使用的。这不仅仅意味着“经过身份验证的人”;它意味着Django假设你的内容编辑者可以被信任去做正确的事情。

这反过来意味着,编辑内容没有审批流程——如果你信任你的用户,就不需要任何人来批准他们的编辑。另一个含义是,权限系统虽然强大,但在写这篇文章时并不支持按对象限制访问。如果你信任某人编辑自己的故事,你也信任他们不会在没有权限的情况下编辑其他人的故事。

“… 编辑 …”

Django管理界面的主要目的是让人们编辑数据。这一看似显而易见,但实际上有一些微妙而强大的影响。

例如,尽管管理界面对于查看数据非常有用(如前所述),但它并不是为了这个目的而设计的。比如,注意到没有“可以查看”的权限(见第12章)。Django假设,如果人们被允许在管理界面查看内容,他们也被允许编辑它。

还有一个更重要的事情是,管理界面没有任何接近“工作流程”的东西。如果某个任务需要一系列步骤,管理界面并不支持强制这些步骤按特定顺序完成。Django的管理界面专注于编辑,而不是围绕编辑的活动。这种对工作流程的回避也源于信任原则:管理界面的理念是,工作流程是人事问题,而不是需要在代码中实现的东西。

最后,注意管理界面缺乏聚合功能。也就是说,没有支持显示总数、平均值等功能。再次强调,管理界面是用于编辑的——预计你会为其他所有内容编写自定义视图。

“… 结构化内容”

与Django的其他部分一样,管理界面希望你处理结构化数据。因此,它只支持编辑存储在Django模型中的数据;对于其他任何内容,比如存储在文件系统中的数据,你需要自定义视图。

结束语

现在应该很清楚,Django的管理界面并不试图满足所有人的需求;相反,我们选择紧紧聚焦于一件事,并把这件事做到极致。

在扩展Django的管理界面时,这种理念仍然适用(注意“可扩展性”并没有出现在我们的目标中)。因为自定义的Django视图可以做任何事情,并且可以很容易地与管理界面视觉集成(如下一节所述),所以内置的自定义管理界面的机会在设计上是有限的。

你应该记住,管理界面“只是一个应用”,尽管它非常复杂。它并没有做任何一个有足够时间的Django开发者无法重现的事情。未来可能会有人开发出基于不同假设的管理界面,因此会有不同的表现。

最后,我们要指出的是,在写这篇文章时,Django开发者正在开发一个新的管理界面版本,允许更灵活的自定义。到你阅读这篇文章时,这些新功能可能已经融入到正式的Django版本中。想要了解更多,可以问问Django社区的人“newforms-admin”分支是否已经整合。

管理应用已经经历了很多改进,以允许更灵活的自定义,但在我看来,“管理的禅意”中的许多内容仍然成立。

5

以下这个自定义的 ModelAdmin 是我目前想到的最佳解决方案:

class UserModelAdmin(ModelAdmin):
    def get_urls(self):
        urls = super(UserModelAdmin, self).get_urls()
        info = self.model._meta.app_label, self.model._meta.module_name
        select_list_url = patterns('',
            url(r'^selectlist/$', self.selectlist_view, 
                name='%s_%s_select' % info)
        )
        return select_list_url + urls

    def selectlist_view(self, request, extra_context=None):
        temp_list_display_links = self.list_display_links
        self.list_display_links = (None, )
        response = self.changelist_view(request, extra_context)
        self.list_display_links = temp_list_display_links
        return response

撰写回答