定制化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. Luogu P1802 5倍经验日_KEY

    题目传送门 ·背包 这可以说是一道背包的变形. 首先需要考虑到的是如何将ta转换为一个正常 的背包. 这些数据有一个让我们都十分不爽的地方就是有两个值. 所以我们就设置一个基准值,将失败的经验值当做基 ...

  2. Spring框架之Filter应用

    在web.xml中进行配置,对所有的URL请求进行过滤,就像"击鼓传花"一样,链式处理. 配置分为两种A和B. 在web.xml中增加如下内容: <filter> &l ...

  3. svn 撤销 已提交的修改

    1.保证我们拿到的是最新代码:  svn update  假设最新版本号是28.  2.然后找出要回滚的确切版本号:  svn log [something]  假设根据svn log日志查出要回滚的 ...

  4. hdu5305 Friends(dfs,多校题)

    Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  5. 180601-MySql性能监控工具MyTop

    文章链接:https://blog.hhui.top/hexblog/2018/06/01/180601-MySql性能监控工具MyTop/ mysql 性能监控小工具之 mytop 参考: How ...

  6. 制作一个App的完整流程是哪些

    APP开发流程其实并不复杂,但是对于客户来说,.一般移动APP开发都离不开UI设计师.前端开发.后端开发.测试专员.产品经理等,由于他们的工作性质都不一样,我们且先把APP软件开发项目分为三个阶段: ...

  7. Java学习 · 初识 异常机制

    异常机制 1.   程序中的异常 a)     b)    面对异常如何解决 i.           由开发者通过if-else来解决 代码臃肿 程序员需要花费很大精力 ii.           ...

  8. CSP201703-1:分蛋糕

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  9. commons-lang源码解析之StringUtils

    apache的commons工具包是平时使用最多的工具包之一,对其实现方式需要具体了解.commons-lang version 3.1 empty和blank的区别 StringUtils中判断St ...

  10. 1053 Path of Equal Weight (30 分)(树的遍历)

    题目大意:给出树的结构和权值,找从根结点到叶子结点的路径上的权值相加之和等于给定目标数的路径,并且从大到小输出路径 #include<bits/stdc++.h> using namesp ...