Django管理后台:如何添加自定义列表视图?
我想在管理后台提供一个自定义的视图,这个视图跟 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 个回答
我不太清楚为什么,但就我个人而言,我倾向于重写(或扩展)特定模型的更改列表模板,而不是直接修改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”分支是否已经整合。
管理应用已经经历了很多改进,以允许更灵活的自定义,但在我看来,“管理的禅意”中的许多内容仍然成立。
以下这个自定义的 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