真的骄傲梦想家园
专业源于兴趣和努力

自定义admin表单
这足以让我们惊讶好几分钟,所有的代码我们都不需要写。
当我们调用admin.site.register(Poll)时,Django只让你编辑这个对象并”推测“怎么把它显示在管理页面上。
很多时候,你可能想要控制admin的样式和功能。你可以在你注册对象的时候把选项告诉Django来实现。
让我们看一下在编辑表单中是怎样实现重新排序字段的。用下面的代码来替换admin.site.register(Poll):
  class PollAdmin(admin.ModelAdmin):
      fields = ['pub_date', 'question']

  admin.site.register(Poll, PollAdmin)
你将遵循这个模式——创建一个admin模型对象,然后把它传递给admin.site.register()的第二个参数——任何时候你需要修改admin的选项都是修改一个对象。上面具体的改变是"Publication date"字段在"Question"字段的前面:


只有两个字段并不会给人留下深刻的印象,但当admin表单包含有大量字段的时候,选择一个直观的排序方式就是一个重要的细节了。
并且,你可能想要把这些大量的表单字段分割归类为字段集:
  class PollAdmin(admin.ModelAdmin):
      fieldsets = [
          (None,               {'fields': ['question']}),
          ('Date information', {'fields': ['pub_date']}),
      ]

  admin.site.register(Poll, PollAdmin)
字段集中每个tuple的第一个元素是字段集的标题。现在我们的表单看起来像这样:


你可以给每个字段集指定任意的HTML样式。Django提供有一个"collapse"样式,它让每个具体的字段集在初始化时显示为折叠的。
当你的一个很长的表单中包含了许多不常用的字段时,这个样式就显得很实用了:
  class PollAdmin(admin.ModelAdmin):
      fieldsets = [
          (None,               {'fields': ['question']}),
          ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
      ]

 
添加关联的对象
OK,我们已经有了一个Poll admin页面。但是一个Poll有多个Choice,管理页面并没有显示Choices。
好的。
有两种方法可以解决这个问题。第一种方法是注册admin Choice,就像我们注册Poll那样。这很容易:
  from mysite.polls.models import Choice

  admin.site.register(Choice)
现在Django admin中的"Choices"已经可用了。这个"Add choice"看起来像这样:


在这表单中,"Poll"字段是一个选择框,包含数据库所有的poll。Django知道,外键在admin中代表一个<select>框。
在我们的例子中,只有poll存在外键。
还注意到"Poll"旁边的"Add Another"链接。每个包含有和其它对象构成外键关系的对象都会有这个链接。
当你单击"Add Another"时,你会得到一组带有"Add poll"表单的窗体。
如果你在窗体中添加一个poll并点击"Save",Django把这个poll保存到数据库中并把它作为选项动态添加到"Add choise"中。
但实际上,这是一种低效的添加Choice对象到系统中的做法。当你在创建Poll对象时,如果你能给它直接添加Choice就更好了。让我们实现它吧。
移去注册Choice模型的register()方法调用。然后,编辑Poll的注册代码:
  class ChoiceInline(admin.StackedInline):
      model = Choice
      extra = 3

  class PollAdmin(admin.ModelAdmin):
      fieldsets = [
          (None,               {'fields': ['question']}),
          ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
      ]
      inlines = [ChoiceInline]

  admin.site.register(Poll, PollAdmin)
这些代码告诉Django:"Choice对象在Poll的admin page中编辑。默认,为3个choice提供足够的字段。"
加载"Add poll"页面看看它是什么样子的:


它是这样工作的:有3个与Choice相关联的栏——在extra中指定的——每次你返回到一个已经创建的对象的"Change"页面时,你都会得到另外3个的额外栏。
但还是有个小问题。它占据了太多的空间来显示关联对象Choice的所有输入域。对于这个问题,Django提供一种制表的方式来显示关联的对象;
你只需要修改一下ChoiceInline的声明就行了:
  class ChoiceInline(admin.TabularInline):
      #...
使用TabularInline (取代StackedInline), 关联的对象显得更紧凑,它是基于表的格式:

自定义admin change list
现在Poll admin页面已经很好了,让我们对"change list"页面做些优化——它用于显示系统中所有的poll。
这是它看起来的样子:


默认,Django显示每个对象的str()。但有时候如果我们能显示个别字段的话会更有效果。
要做到这点,只需使用list_display admin选项,这是一个用于在对象的change list页面内把字段名作为列名显示的tuple:
  class PollAdmin(admin.ModelAdmin):
      # ...
      list_display = ('question', 'pub_date')
  Just for good measure, let's also include the was_published_today custom method from Tutorial 1:

  class PollAdmin(admin.ModelAdmin):
      # ...
      list_display = ('question', 'pub_date', 'was_published_today')
现在,poll change list页面看起来是这样:


你可以点击列头来排序这些值——除了was_published_today头外,因为排序不支持任何方法的输出值。
还注意到was_published_today列头默认是它的方法名(使用下划线替换空格)。但你可以通过给方法一个简短的属性描述来改变这个名:
  def was_published_today(self):
      return self.pub_date.date() == datetime.date.today()
  was_published_today.short_description = 'Published today?'
让我们对Poll change list页面添加另外的改进:过滤。添加下面的代码到PollAdmin中:
  list_filter = ['pub_date']
添加了一个"Filter"侧边栏让人们使用pub_date字段过滤change list:


这个过滤器显示的样式取决于你要过滤的字段的类型。
因为pub_date是DateTimeField,Django知道给DateTimeField一个默认的过滤器:

  "Any date","Today","Past 7 days","This month","This year"。
现在变得更好了。让我们添加一些检索功能:
  search_fields = ['question']
为change list添加了一个检索框。当有人输入检索值时,Django会检索question字段。
你可以使用多个检索字段——尽管它使用的是LIKE查询,既保证了自身的可读性,也保证了你的数据库的效率了。
最后,因为Poll对象包含有日期,如果能向下操作就更方便了。添加这行代码:
  date_hierarchy = 'pub_date'
它在change list页面添加了一个日期分层的导航。在上层,它显示所有可用的年份。然后向下显示月和日。
现在也是一个注意change lists给你提供了免费的分页功能的好时机。
默认是每页显示50条记录。Change-list的分页,检索,过滤,日期分层和列头排序都按照你想要的效果工作了。 

posted on 2008-12-02 21:05  真的骄傲  阅读(2140)  评论(3编辑  收藏  举报