定制化admin表单

通过使用admin.site.register(Question)注册Question模型,Django可以构造默认的表单。通常,可以通过对象的注册机制来告诉Django我们想要注册的选项,来定制化admin表单。

让我们通过重新排列表单的字段来看看它是如何工作的,打开polls/admin.py文件,使用如下代码替换admin.site.register(Question)

from django.contrib import admin
from .models import Question class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date', 'question_text'] admin.site.register(Question, QuestionAdmin)

上述代码,创建一个admin模型类,将其作为第二个参数传递给admin.site.register()。这个特别的改变使得"Date published"字段位于"Question"之上,如下图所示:

上述改变对于仅仅两个字段并没有什么改善,但是对于有许多字段的admin表单来说,选择一个直观的排序是非常重要的一个使用细节。编辑polls/admin.py代码如下所示:

from django.contrib import admin
from .models import Question class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date']}),
] admin.site.register(Question, QuestionAdmin)

fieldsets的每个元组的第一个元素是fieldset的标题,下图所示是我们修改后的表单:

添加相关对象

现在,我们有了问题管理页面,但是每个问题有多个选项,并且管理页面没有显示这些选项。有两种方法解决这个问题,第一种方法在admin中注册Chice,就像操作Question一样,这个很容易。打开polls/admin.py文件,添加如下代码:

from .models import Question, Choice

admin.site.register(Choice)

现在在Django管理页面,就可以增加选项,表单如下图所示:

在该表单中,"Question"字段是一个下拉选择框,包含了数据中的每个question。在管理页面Django会把ForeignKey识别成一个下拉选择框。在我们的例子中,仅存在一个question。

当我们点击"Add Another"或者"+(加号)"时,我们会获得一个弹出框,上面显示的添加问题表单。如果在该窗口增加一个问题并且点击"保存(save)",Django会将该问题保存到数据库中,并且将其动态添加到"增加选项"选择框中,如下图所示:

但是,实际上这是一种低效率的方式在我们的系统中添加Choice,如果在我们创建Question时,可以批量添加选择项的话就会好很多。接下来我们就使用这种方式,打开polls/admin.py文件,编辑代码如下:

from django.contrib import admin
from .models import Question, Choice class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3 class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] admin.site.register(Question, QuestionAdmin)

上述代码告诉Django:在Question管理页面Choice对象被修改。默认情况下,为3个选项提供了足够的字段。加载"增加问题"页面将会看到如下图示:

在当前3个位置的底部,我们会看到"增加另一个Choice"链接。如果点击该链接,将会添加一个新的插槽;如果想删除添加的插槽,可以点击该插槽右侧的"X",该操作无法删除原始的3个插槽,如下截图所示:

然而,存在一个小问题。对于进入被关联的Choice对象,显示其所有字段会消耗很多的屏幕空间。因此Django提供了一种扁平化的对象显示,打开polls/admin.py文件,修改代码如下所示:

class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3

使用TabularInline代替StackedInline,管理对象显示成紧凑的,表格化的格式,如下图所示:

注:表格有个额外的"删除"列,允许删除通过"增加另一个choice"按钮创建并且保存的行。

定制化改变列表

默认情况下,Django显示每个对象的str(),但是有的时候显示独立的字段可能对我们更有用。这样做,使用list_display管理选项,它是要显示字段名字的元组,作为对象的列显示在修改页面,打开polls/admin.py文件,修改代码如下所示:

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

为了更好的测试,我们也将was_published_recently()方法包含在该方法,如下代码:

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

现在问题改变页面看起来如下入所示:

可以通过点击列头来对表进行排序,was_published_recently头是例外,因为排序不支持任意方法的输出。可以通过给该方法添加一些属性来改善该问题,打开polls/models.py文件,修改其代码如下:

class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published') def __str__(self):
return self.question_text def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'

关于该方法的更多信息,请参考list_display。再次修改polls/admin.py文件并且为问题改变列表页面增加修改,过滤器使用list_filter。在QuestionAdmin中增加如下行:

list_filter = ['pub_date']

上述增加一个"过滤器"侧边栏,用户可以通过pub_date字段用过滤器来查找改变列表,如下图所示:

过滤器显示的类型依赖于你要过滤的类型。因为pub_date是一个DateTimeField,所以Django知道适配适合的过滤器选项:"任意日期"、"今天"、"过去7天"、"本月"、"今年"。让我们添加一些搜索内容,打开polls/admin.py文件,在QuestionAdmin中增加如下行:

search_fields = ['question_text']

页面显示如下如所示:

在修改列的上方增加了一个搜索框,当用户进入搜索项时,Django将会搜做question_text字段。你可以根据需要使用任意数量的字段,因为后台使用LIKE查询,限制搜索字段的可用数量对数据库做查询操作来时比较容易。

默认情况,每页显示100项,为了更好的页面显示,可以使用分页技术。通常情况下分页搜索框过滤器日期层次列头排序是综合使用来实现你想要的页面。

自定义管理外观

自定义项目模板:在项目目录(包含manage.py文件的目录)中创建一个templates目录,模板可以放在任何Django能够访问的目录,但是放在项目目录中是最方便的。打开项目配置文件:mysite/settings.py,在该文件的TEMPLATES配置中添加一个DIRS选项,其代码如下所示:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

当加载Django模板时,DIRS是要去检查的一系列文件目录,是一个搜索路径。在templates中创建一个名为admin的目录,将Django源代码(django/contrib/admin/templates)中默认的Django管理模板(admin/base_site.html)拷贝到刚才目录中去。

接下来,仅修改这个文件并且替换{{ site_header|default:_('Django administration') }}(包括花括号)为你自己满意的站点名字。其代码如下所示:

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}

通过上面这种方法,我们学会了如何重写模板。在实际的项目中,可以使用django.contrib.admin.AdminSite.site_header属性更加容易的实现特性自定义。该模板文件中包含了很多类似{% block branding %}{{ title}}的文本内容。花括号+百分号和双花括号都是Django的模板语言,当Django渲染模板文件时,这些模板语言将会处理最终的HTML页面。

注:Django所有的默认管理模板都是可以重写的,重写模板就像我们之前修改base_site.html那样,从默认目录拷贝到自定义目录中,然后修改即可。

自定义应用模板:聪明的读者可能发现,默认情况DIR是空的,那么Django如何找到默认的管理模板呢?该问题的答案是:由于APP_DIRS是设置True,Django会在每个应用包里面查找templates/子目录,用作后备(不要忘记django.contrib.admin也是一个应用)。

模板文件加载详细地讲解Django如何查找模板。

自定义管理索引页面:默认情况,它显示的是INSTALLED_APPS中注册在管理应用中的所有应用,按字母表排序。

自定义的模板是admin/index.html。操作跟上部分的admin/base_site.html相同,编辑该文件,将会看到它使用了一个名叫app_list的模板变量,该变量包含了Django的每个installed应用。

Django 2.0 学习(10):Django 定制化的更多相关文章

  1. Django 2.0 学习(07):Django 视图(进阶-续)

    接Django 2.0 学习(06):Django 视图(进阶),我们将聚焦在使用简单的表单进行处理和精简代码. 编写简单表单 我们将用下面的代码,来替换之前的detail模板("polls ...

  2. Django 2.0 学习(04):Django数据库

    数据库设置/配置 打开mysite/settings.py,我们会发现Django是用的是默认的数据库SQLite,如下图所示: Django也是支持其它数据库的,比如PostgreSQL.MySQL ...

  3. Django 2.0 学习(12):Django 模板语法

    Django 模板语法 一.模板 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板. 二.模板语法 模板语法变量:{{ }} 在Django模板中遍历复杂数据结构的关键是句点字 ...

  4. Django 2.0 学习(19):Django 分页器

    Django 分页器 要使用Django实现分页功能,必须从Django中导入Paginator模块(painator - 分页器) views.py from django.shortcuts im ...

  5. Django 2.0 学习(16):Django ORM 数据库操作(下)

    Django ORM数据库操作(下) 一.增加表记录 对于表单有两种方式: # 方式一:实例化对象就是一条表记录france_obj = models.Student(name="海地&qu ...

  6. Django 2.0 学习(09):Django 静态文件(样式和背景图片)

    应用的定制化:静态文件 首先,在polls目录中创建一个名叫static的目录.Django会在该目录里面查找静态文件,类似于Django在polls/template目录下查找模板文件. Djang ...

  7. Django 2.0 学习(06):Django 视图(进阶)

    概述 Django中的特方法,该方法代表了Django的Web页面,并且视图具有特定的模板.以博客应用为例进行说明,在博客应用中应该包含下面的视图: 博客主页:显示最近的一些记录: 详细页面:单个详细 ...

  8. Django 2.0 学习(01):Django初识与安装

    Django(Python Web框架) Django是一个开放源代码的Web框架,用Python写的.采用了MTV的框架模式,即模型M,模板T和视图V.它最初被开发是用来管理以新闻内容为主的网站,即 ...

  9. Django 2.0 学习

    Django django是基于MTV结构的WEB框架 Model 数据库操作 Template 模版文件 View 业务处理 在Python中安装django 2.0 1 直接安装 pip inst ...

随机推荐

  1. MySQL入门第二天——记录操作与连接查询

    常见SQL语法,请参见w3school:http://www.w3school.com.cn/sql/sql_distinct.asp 易百教程:http://www.yiibai.com/sql/f ...

  2. BZOJ2330_糖果_KEY

    题目传送门 看题目可知这是一道差分约束的题目. 根据每种关系建边如下: 对于每种情况建边,然后跑一边SPFA.(最长路) 因为可能会有自环或环的情况,都不可能存在. 跑SPFA时记录入队次数,超过N弹 ...

  3. 北京Uber优步司机奖励政策(4月6日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  4. spring源码-国际化-3.5

    一.国际化在实际代码中是非常常见的一中方式.为了结合web做一下语言上面的切换,而达到展示的目的. 二.这里呢,主要是介绍spring中对于国际化做了哪些处理. 三.实现方式 1)xml配置 < ...

  5. eclipse报这个错误org.eclipse.swt.SWTError: No more handles (eclipse 和 TeamViewer 冲突)

    错误:  org.eclipse.swt.SWTError: No more handles     at org.eclipse.swt.SWT.error(SWT.java:4387)     a ...

  6. 「日常训练」Two Substrings(Codeforces Round 306 Div.2 A)

    题意与分析 一道非常坑的水题.分析醒了补. 代码 #include <bits/stdc++.h> #define MP make_pair #define PB emplace_back ...

  7. C++ 基础面试题-1

    请说出下面代码在32位系统下的输出内容 /* ** 2018/03/21 21:43:00 ** Brief: ** Author:ZhangJianWei ** Email:Dream_Dog@16 ...

  8. katalon系列三:Project Setting-项目设置

    安装完katalon后,用QQ邮箱注册并登陆,然后新建一个项目.点击菜单Project-Project Setting打开项目设置,接下来介绍几个你可能会用到的设置. 1.Text Design-We ...

  9. jmeter属性设置

    使用${__setProperty(newuserid,1,)}函数对属性进行设置 2.使用${__P(userid)}函数在其他线程组中引用该属性 备注: 1.JMeter属性在测试脚本的任何地方都 ...

  10. ORACLE高级部分内容

    1.pl/sql基本语句 DECLARE BEGIN END; / 循环语句 DECLARE I  NUMBER(2):=1; BEGIN WHILE I<100 LOOP I:=I+1; EN ...