Django 2.0 学习(10):Django 定制化

时间:2023-03-09 18:59:00
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"之上,如下图所示:

Django 2.0 学习(10):Django 定制化

上述改变对于仅仅两个字段并没有什么改善,但是对于有许多字段的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的标题,下图所示是我们修改后的表单:

Django 2.0 学习(10):Django 定制化

添加相关对象

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

from .models import Question, Choice

admin.site.register(Choice)

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

Django 2.0 学习(10):Django 定制化

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

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

Django 2.0 学习(10):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个选项提供了足够的字段。加载"增加问题"页面将会看到如下图示:

Django 2.0 学习(10):Django 定制化

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

Django 2.0 学习(10):Django 定制化

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

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

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

Django 2.0 学习(10):Django 定制化

注:表格有个额外的"删除"列,允许删除通过"增加另一个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')

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

Django 2.0 学习(10):Django 定制化

可以通过点击列头来对表进行排序,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字段用过滤器来查找改变列表,如下图所示:

Django 2.0 学习(10):Django 定制化

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

search_fields = ['question_text']

页面显示如下如所示:

Django 2.0 学习(10):Django 定制化

在修改列的上方增加了一个搜索框,当用户进入搜索项时,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应用。