Django 2.0 学习(10):Django 定制化
定制化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 定制化的更多相关文章
- Django 2.0 学习(07):Django 视图(进阶-续)
接Django 2.0 学习(06):Django 视图(进阶),我们将聚焦在使用简单的表单进行处理和精简代码. 编写简单表单 我们将用下面的代码,来替换之前的detail模板("polls ...
- Django 2.0 学习(04):Django数据库
数据库设置/配置 打开mysite/settings.py,我们会发现Django是用的是默认的数据库SQLite,如下图所示: Django也是支持其它数据库的,比如PostgreSQL.MySQL ...
- Django 2.0 学习(12):Django 模板语法
Django 模板语法 一.模板 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板. 二.模板语法 模板语法变量:{{ }} 在Django模板中遍历复杂数据结构的关键是句点字 ...
- Django 2.0 学习(19):Django 分页器
Django 分页器 要使用Django实现分页功能,必须从Django中导入Paginator模块(painator - 分页器) views.py from django.shortcuts im ...
- Django 2.0 学习(16):Django ORM 数据库操作(下)
Django ORM数据库操作(下) 一.增加表记录 对于表单有两种方式: # 方式一:实例化对象就是一条表记录france_obj = models.Student(name="海地&qu ...
- Django 2.0 学习(09):Django 静态文件(样式和背景图片)
应用的定制化:静态文件 首先,在polls目录中创建一个名叫static的目录.Django会在该目录里面查找静态文件,类似于Django在polls/template目录下查找模板文件. Djang ...
- Django 2.0 学习(06):Django 视图(进阶)
概述 Django中的特方法,该方法代表了Django的Web页面,并且视图具有特定的模板.以博客应用为例进行说明,在博客应用中应该包含下面的视图: 博客主页:显示最近的一些记录: 详细页面:单个详细 ...
- Django 2.0 学习(01):Django初识与安装
Django(Python Web框架) Django是一个开放源代码的Web框架,用Python写的.采用了MTV的框架模式,即模型M,模板T和视图V.它最初被开发是用来管理以新闻内容为主的网站,即 ...
- Django 2.0 学习
Django django是基于MTV结构的WEB框架 Model 数据库操作 Template 模版文件 View 业务处理 在Python中安装django 2.0 1 直接安装 pip inst ...
随机推荐
- Java基础——注解
一.概述 引自百度百科: 定义:注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法. ...
- c#调用c++库函数
如果是非托管的,就用DllImport,举例 using System; using System.Runtime.InteropServices; class MainApp ...
- jsp内置的对象【jsp可用数据容器】
jsp的内置对象用法:可以存放数据进去,本身页面可以调用,发生页面请求时,请求目标可以调用 理解:jsp就是一个大容器,有请求,响应等内置对象,会话需要从请求容器中提取 请求中内置session,发出 ...
- BZOJ3293_分金币_KEY
题目传送门 设x[i]表示i+1向i传的糖果数,x[n]表示1向n传的糖果数,a'=(a[1]+...a[N])/N a[1]+x[1]−x[n]=a' a[2]+x[2]−x[1]=a' a[3]+ ...
- .net core 基于multipart/form-data的文件上传,这里以图片上传为例
首先传递的数据格式大概如下: 然后就可以在后端获取数据了:直接上代码了哈: [HttpPost] ///分别获取 data数据和调用图片上传方法 public async Task< ...
- Visual studio 2010 TFS地址解析,让团队资源管理器不再显示IP地址
第一步: 找到名为hosts的配置文件(路径C:\Windows\System32\drivers\etc\hosts)用记事本打开并写入需要的配置,例如我用到的是TFS服务器的IP地址为192.16 ...
- PHP数组中插入元素
1. array_unshift()数组头插入新元素 $fruits = array('apple','pear','banana','orange'); array_unshift($fruits, ...
- Rails导出CSV
版本 ruby 1.9 rails 3.2 完整代码 #引入CSV标准类库 require 'csv' class PeopleController < ApplicationControl ...
- Servlet的5种方式实现表单提交(注册小功能)
Servlet的5种方式实现表单提交(注册小功能),后台获取表单数据 用servlet实现一个注册的小功能 ,后台获取数据. 注册页面: 注册页面代码 : <!DOCTYPE html> ...
- ServletContext详解 以及用法
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放.request,一个用户可有多个:session,一个用户一个:而servletContext,所 ...