django管理员
Django管理员
Django为潜在的开发人员提供了许多功能:成熟的标准库,活跃的用户社区以及Python语言的所有优点。 尽管其他Web框架也可以提出类似的要求,但Django的独特资产是其内置的管理应用程序-admin。
管理员提供了开箱即用的高级创建-读取-更新-删除(CRUD)功能,从而消除了重复工作。 对于开发中的许多Web应用程序来说,这是关键,当程序员可以快速探索其数据库模型时,以及在部署中,当非技术性最终用户可以使用管理员来添加和编辑站点内容时,这就是关键。
在现实世界中,总是需要执行一些自定义。 Django文档提供了许多有关重新设置管理员基本外观的准则,并且Django本身包含一些简单的方法来覆盖部分管理员行为。 如果您需要做更多呢? 你从哪里开始? 本文提供了一些有关高级管理员自定义的准则。
管理员快速浏览
大多数Django开发人员都熟悉admin的默认功能。 为了快速查看,首先通过编辑顶级urls.py启用清单1中的管理员。
清单1.在urls.py中启用管理员
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Uncomment the next line to enable the admin:
(r'^admin/(.*)', admin.site.root),
)
您还需要将django.contrib.admin
应用程序添加到settings.INSTALLED_APPS
。
在继续之前,建议任何打算广泛自定义管理员的人熟悉源代码。 对于支持快捷方式或符号链接的操作系统,将其制作为管理应用程序可能很有用。
管理员位于Django软件包中。 假设它是使用setuptools安装的,则admin位于django / contrib / admin下的站点包中。 这是一个从项目到Django管理源的符号链接示例,您可以根据您的操作系统和Django安装位置进行自定义,以方便复制和参考:
$ ln -s /path/to/Python/install/site-packages/django/contrib/admin admin-source
admin.autodiscover()
方法遍历settings.INSTALLED_APPS中的每个应用程序,并查找名为admin.py的文件。 通常将其放置在应用程序目录的顶层,与models.py处于同一级别。
示例应用程序需要清单2中提供的models.py。下面显示相应的admin.py。
清单2.此应用程序的样本models.py
from django.db import models
class Document(models.Model):
'''A Document is a blog post or wiki entry with some text content'''
name = models.CharField(max_length=255)
text = models.TextField()
def __unicode__(self):
return self.name
class Comment(models.Model):
'''A Comment is some text about a given Document'''
document = models.ForeignKey(Document, related_name='comments')
text = models.TextField()
此时,您可以通过运行Django开发服务器来调用admin:
python manage.py runserver
管理员位于默认位置http:// localhost:8000 / admin /。 登录后,您会看到下面显示的基本管理屏幕。
图1.基本的Django管理屏幕
请注意,您的模型尚不可用,因为您尚未创建admin.py。 清单3演示了允许您在admin中使用模型的代码。
清单3.一个示例admin.py
from django.contrib import admin
from more_with_admin.examples import models
class DocumentAdmin(admin.ModelAdmin):
pass
class CommentAdmin(admin.ModelAdmin):
pass
admin.site.register(models.Document, DocumentAdmin)
admin.site.register(models.Comment, CommentAdmin)
现在,当您在管理员中重新加载主页时,您会看到可用的新模型,如下所示。
图2.准备支持自定义模型的Django管理员
自定义管理模型页面
理解如何自定义管理员而不破解Django源代码的关键是要记住,管理员是一个普通的Django应用程序,就像其他应用程序一样。 首先,这意味着Django模板继承系统适用。
Django的模板搜索顺序始终优先于您自己项目的模板,而不是任何系统模板。 此外,管理员在尝试使用默认值之前会尝试搜索与每个模型匹配的硬编码模板。 这为轻松定制提供了一个切入点。
首先,通过编辑项目的settings.py确保Django将在模板目录中查找。
清单4.编辑settings.py以查看模板目录
TEMPLATE_DIRS = (
"/path/to/project/more_with_admin/templates",
"/path/to/project/more_with_admin/examples/templates",
)
然后在您的项目中创建以下目录:
$ mkdir templates/admin/examples/document/
$ mkdir templates/admin/examples/comment/
Django管理员的特殊行为是在使用系统模板呈现该管理页面之前,先检查应用程序名称的目录(此处为examples
),然后检查模型名称( document
和comment
)。
覆盖单个模型添加/编辑页面
管理员用于添加和编辑模型实例的页面的名称为change_form.html。 首先在Document
模型目录中创建一个名为template / admin / examples / document / change_form.html的页面,然后在其中放置Django模板继承行: {% extends "admin/change_form.html" %}
。
现在您可以自定义了。 花一些时间来熟悉真正的admin / change_form.html的内容。 它合理地组织成可以覆盖的模板块,但是某些自定义项可能需要批量复制块。 尽管如此,使用基于块的模板替代总是比复制整个页面更好。
您想对添加/编辑页面进行哪些自定义? 也许您想为系统中的每个Document
显示五个最新注释的预览。
首先,创建一些示例内容。
清单5.使用Django shell创建带有几个注释的示例Document
$ python manage.py shell
In [1]: from examples import models
In [2]: d = models.Document.objects.create(name='Test document',
text='This is a test document.')
In [3]: for c in range(0, 10):
...: models.Comment.objects.create(text='Comment number %s' % c, document=d)
现在,管理员列表页面显示一个Document
。 选择该Document
以显示如下所示的默认添加/编辑页面。
图3.具有Document
默认添加/编辑页面
请注意,相关评论不会以任何方式显示。 在管理员中显示相关模型的标准方法是使用功能强大的Inline
类。 Inline
类允许管理员用户在单个页面上编辑或添加多个相关模型。 要查看内inlines
,请编辑应用程序admin.py以匹配清单6。
清单6.将相关的模型注释添加到Document
admin
from django.contrib import admin
from more_with_admin.examples import models
class CommentInline(admin.TabularInline):
model = models.Comment
class DocumentAdmin(admin.ModelAdmin):
inlines = [CommentInline,]
class CommentAdmin(admin.ModelAdmin):
pass
admin.site.register(models.Document, DocumentAdmin)
admin.site.register(models.Comment, CommentAdmin)
图4显示了添加TabularInline
控件后的新添加/编辑页面。
图4.将注释模型添加为Inline
之后的文档添加/编辑页面
这当然是强大的,但是如果您只想快速查看注释预览,则可能会显得过高。
您可以在此处采取两种方法。 一种是使用Django管理小部件界面编辑与inline
关联HTML小部件。 Django文档详细描述了小部件。 另一种方法是直接修改添加/编辑模板。 当您完全不想使用任何特定于管理员的功能时,此方法最有用。
如果你不想让注释(可能是因为用户没有足够的权限)的任何编辑,但你希望他们能够看到的评论,你可以修改change_form.html。
Django管理员提供的变量
要将功能添加到模型实例页面,您需要知道管理员可以使用哪些数据。 下面描述了两个关键变量。
表1.定制管理模板所需的变量
变量 | 描述 |
---|---|
object_id | 这是被编辑对象的主键。 如果要自定义特定的实例页面(例如“文档”),这就是您所需要的。 |
content_type_id | 如果要覆盖多种类型的模型页面,请使用此方法查询ContentTypes 框架以获取模型的名称。 请参阅相关主题有关内容类型的详细信息。 |
创建要包含在管理页面中的模板标签
列出相关注释需要的代码不能直接输入到Django模板中。 最好的解决方案是使用模板标签。 首先,创建模板标签目录和__init__.py文件:
$ mkdir examples/templatetags/
$ touch examples/templatetags/__init__.py
创建一个名为examples / templatetags / example_tags.py的新文件,并添加以下代码。
清单7.用于检索给定文档ID的注释的模板标记
from django import template
from examples import models
register = template.Library()
@register.inclusion_tag('comments.html')
def display_comments(document_id):
document = models.Document.objects.get(id__exact=document_id)
comments = models.Comment.objects.filter(document=document)[0:5]
return { 'comments': comments }
因为这是一个包含标记,所以您需要创建相应的模板文件:comments.html。 编辑examples / templates / comments.html文件,然后输入清单8中的代码。
清单8.用于显示一组评论预览的模板
{% for comment in comments %}
<blockquote>{{ comment.text }}</blockquote>
{% endfor %}
现在是时候将其添加到管理页面中了。 CommentInline
中对CommentInline
的引用, CommentInline
本地版本的change_form.html进行清单9所示的更改。
清单9.在添加/编辑页面中包含模板标签
{% extends "admin/change_form.html" %}
{% load example_tags %}
{% block after_field_sets %}
{% if object_id %}{% display_comments object_id %}{% endif %}
{% endblock %}
在尝试使用object_id
之前检查它的存在很重要,因为change_form.html也用于创建新实例,在这种情况下object_id
尚不可用。 after_field_sets
块只是admin中作为扩展点提供的众多块之一。 有关其他信息,请查阅change_form.html源页面。
图5显示了更新后的表单。
图5.包含定制模板标记后的文档添加/编辑页面
修改管理员行为
模板替代只能做很多事情。 如果您想更改管理员的实际流程和行为怎么办? 破解源代码是一种可能,但这会将您锁定在更新时使用的特定版本的Django。
覆盖AdminModel
方法
默认情况下,单击管理员中的“ 保存 ”会将用户返回到列表页面。 通常,这很好,但是如果您想直接进入管理员外部对象的预览页面怎么办? 这是开发内容管理系统(CMS)时的常见用例。
管理应用程序中的大多数功能都附加到admin.ModelAdmin
类。 这是对象从admin.py中继承的类。 您可以覆盖许多公共方法。 检查admin-source / options.py中的源以获取类定义。
有两种方法可以更改“ 保存”按钮的行为:您可以覆盖admin.ModelAdmin.response_add
,后者负责保存后的实际重定向,或者可以覆盖admin.ModelAdmin.change_view
。 后者稍微简单一些。
清单10.在保存事件之后,指向用户的覆盖页面
class DocumentAdmin(admin.ModelAdmin):
def change_view(self, request, object_id, extra_context=None):
result = super(DocumentAdmin, self).change_view(request, object_id, extra_context)
document = models.Document.objects.get(id__exact=object_id)
if not request.POST.has_key('_addanother') and
not request.POST.has_key('_continue'):
result['Location'] = document.get_absolute_url()
return result
现在,当用户单击“ 保存”时 ,他们将被重定向到预览页面,而不是显示所有文档的列表页面。
通过信号向管理员添加功能
信号是Django中未充分使用的功能,可改善代码的模块化。 信号定义事件,例如保存模型或加载模板,这些事件在Django项目可以侦听和响应的任何地方起作用。 这意味着您可以轻松地增强应用程序的行为,而不必直接修改它们。
管理员提供了应用程序开发人员经常要修改的一项功能:通过django.contrib.auth.models.User
类管理用户。 通常,管理员是添加或修改Django用户的唯一位置,因此很难自定义此有用的类。
想象一下,您希望站点的管理员每次创建新的User
对象时都收到一封电子邮件。 由于User
模型在项目中不是直接可用的,因此似乎要实现此目的的唯一方法似乎是对User
进行子类化或使用诸如创建虚拟概要文件对象之类的间接方法进行修改。
清单11展示了添加一个在保存User
实例时运行的函数是多么容易。 信号通常添加到models.py中。
清单11.使用Django信号通知何时添加新用户
from django.db import models
from django.db.models import signals
from django.contrib.auth.models import User
from django.core.mail import send_mail
class Document(models.Model):
[...]
class Comment(models.Model):
[...]
def notify_admin(sender, instance, created, **kwargs):
'''Notify the administrator that a new user has been added.'''
if created:
subject = 'New user created'
message = 'User %s was added' % instance.username
from_addr = 'no-reply@example.com'
recipient_list = ('admin@example.com',)
send_mail(subject, message, from_addr, recipient_list)
signals.post_save.connect(notify_admin, sender=User)
post_save
信号由Django提供,并在保存或创建模型时触发。 这里的connect()
方法采用两个参数:回调( notify_admin
)和sender
参数,该参数指定此回调仅对User
模型中的保存事件感兴趣。
在回调内部, post_save
信号传递发送者(模型类),该模型的实例以及指示该实例是否刚刚创建的布尔值( created
)。 在此示例中,如果正在创建User
,则该方法发送电子邮件;否则,该方法将发送电子邮件。 否则它什么都不做。
其他的Django提供的信号的名单中提供相关信息 ,以及文档了解如何编写自己的信号。
更深入的修改:添加行级权限
Django管理员通常要求的功能是扩展其权限系统以包括行级权限。 默认情况下,管理员允许对角色和权限进行细粒度的控制,但是这些角色仅适用于类级别:用户可以修改所有文档,也可以不修改。
通常,希望让用户仅修改特定的对象。 这些通常称为行级权限,因为它们反映了仅修改数据库表的特定行的能力,而不是修改表中任何记录的全部权限。 示例应用程序中的一个用例可能是您希望用户只能看到他们创建的文档。
首先,更新models.py以包括创建Document
的属性记录,如下所示。
清单12.更新models.py以记录创建每个Document
的用户
from django.db import models
from django.db.models import signals
from django.contrib.auth.models import User
from django.core.mail import send_mail
class Document(models.Model):
name = models.CharField(max_length=255)
text = models.TextField()
added_by = models.ForeignKey(User,
null=True, blank=True)
def get_absolute_url(self):
return 'http://example.com/preview/document/%d/' % self.id
def __unicode__(self):
return self.name
[...]
接下来,您需要添加代码以自动记录哪个用户创建了Document
。 信号对此不起作用,因为信号无法访问用户对象。 但是, ModelAdmin
类确实提供了一种方法,该方法包括请求,因此将当前用户作为参数。
修改save_model()
方法,如下所示。
清单13.覆盖DocumentAdmin
的方法,以在创建时将当前用户保存到数据库
from django.contrib import admin
class DocumentAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if getattr(obj, 'added_by', None) is None:
obj.added_by = request.user
obj.last_modified_by = request.user
obj.save()
[...]
如果added_by
值为None
,这是一个尚未保存的新记录。 (您还可以检查change
是否为false
,这表示正在添加记录,但是检查added_by
是否为空意味着这也将填充已在管理员外部添加的记录。)
下一个行级权限是将文档列表限制为仅创建文档的用户。 ModelAdmin
类通过称为queryset()
的方法为此提供了一个挂钩,该方法确定任何列表页面返回的默认查询集。
如清单14所示,重写queryset()
以将清单限制为仅由当前用户创建的那些Document。 超级用户可以查看所有文档。
清单14.覆盖列表页面返回的查询集
from django.contrib import admin
from more_with_admin.examples import models
class DocumentAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(DocumentAdmin, self).queryset(request)
# If super-user, show all comments
if request.user.is_superuser:
return qs
return qs.filter(added_by=request.user)
[...]
现在,在管理员中对“ Document
列表”页面的任何请求仅显示由当前用户创建的请求(除非当前用户是超级用户,在这种情况下,将显示所有文档)。
当然,当前没有任何东西可以阻止确定的用户通过了解未经授权的文档的ID来访问其编辑页面。 真正安全的行级权限需要更多方法重写。 由于无论如何总的来说,管理员用户在某种程度上还是值得信赖的,因此有时基本权限足以提供简化的工作流程。
结论
自定义Django管理员确实需要一些有关管理员源代码的知识,但很少受到黑客攻击。 使用正常的Python继承和某些仅适用于Django的功能(例如信号),管理员的结构可以扩展。
与创建一个全新的管理界面相比,自定义管理员的优势很多:
- 随着活动的不断发展,您的应用程序将从Django的进步中受益。
- 管理员已经支持最常见的用例。
- 添加到您的项目中的外部应用程序可以自动与您自己的代码并排管理。
展望Django V1.1,管理员提供了两个经常需要的新功能:可以在列表页面上内联编辑字段和admin action的功能 ,该功能允许一次批量更新许多对象。 两种添加都将消除从头开始编写这些通用功能的需要,同时增加了扩展点以进行其他自定义。
翻译自: https://www.ibm.com/developerworks/opensource/library/os-django-admin/index.html
django管理员