admin 管理员组文章数量: 1086019
2024年3月26日发(作者:update sql 是先删除后插入么)
写你的第一个Django应用 | 第一部分
•
•
•
•
•
原文地址:/en/dev/intro/tutorial01/
Creating a project
•
The development server
•
Database setup
Creating models
Activating models
Playing with the API
从示例学习。
开始之前,请确保 Django 已经安装完毕。先运行 Python,若正常,再输入 import
django。如果运行无误,则说明 Django 已成功安装。
$ python
Python 2.5.2 (r252:60911, Feb 22 2008, 07:57:53)
[GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>>
新建项目(Project)
你可以将你的 project 放置在任何目录下,从终端中,用 cd 命令进入理想的目录,然后运
行命令, startproject mysite,这将创建一个名为 mysite 的项
目,在其文件夹中,还自动生成了 4 个文件:
•
•
•
•
这些文件的作用是:
•
•
•
•
: 这是一个空文件,指示这个目录是 Python 的一个 package。
: 一个命令行工具,可以用来对 Django 项目进行各种操作。
: Django 项目的设置文件。
: Django 项目 URL 声明文件;网站的 "目录"。
运行本地服务器
Django 本身包含一个用纯 Python 语言编写的轻量级服务器,便于快速开发你的项目,而不
用花费过多精力设置服务器,比如 Apache,除非你准备好正式发布网站。
在 mysite 目录中,如果你紧跟着教程到此,可以直接运行命令 python
runserver,启动服务器。你可以看到屏幕出现:
0 errors found.
Django version 1.0, using settings 'gs'
Development server is running at 127.0.0.1:8000/
Quit the server with CONTROL-C.
此文字说明 Django 服务器已启动,可以用浏览器访问 127.0.0.1:8000/ ,如果一切正常,
你将会看到 Django 的起始页。It worked!
设置数据库
接下来,编辑 文件。这个文件是一个普通的 Python 模块,包含模块级别的变量
来规定 Django 设置。现在我们修改关于数据库的设置连接参数,去吻合你将使用的数据库。
•
•
•
•
•
DATABASE_ENGINE -- 数据库引擎,常见的有:"postgresql_psycopg2"、"mysql" 或
"sqlite3"。还可选择 "postgresql" 或 "oracle"。
DATABASE_NAME -- 数据库名称。若使用 SQLite3,数据库名称是数据库文件名和
其保存的绝对路径。
DATABASE_USER -- SQLite3 不用修改,为空。
DATABASE_PASSWORD -- 默认为 localhost。SQLite3 不用修改。
DATABASE_HOST -- 默认为 default。SQLite3 不用修改。
使用 SQLite 数据库最简单,设置 DATABASE_ENGINE 为 sqlite3. 若使用其他类
型的数据库,在此应通过命令创建新的数据库。
当你编辑 文件时,顺便注意一下文件底部 INSTALLED_APPS 设置,默认包含如
下 apps:
•
•
•
•
ttypes
ns
这些是 Django 项目默认包含的应用,比如认证系统、内容类型框架、session 框
架、多网站管理的应用,这些 app 独立存在,可以根据需要保留或删除,也可应
用在其他项目中。
每个 app 至少对应一个数据库表,我们在 mysite 目录中运行如下命令来生成数
据库表:
python syncdb
syncdb 会搜索 INSTALLED_APPS 中的所有 app,生成必要的书库据表。你会看
到提示询问是否要为认证系统创建一个超级用户,输入 yes,根据提示完成。
创建模型
我们现在已经有了一个 mysite 的项目环境,接下来让我们做点事情。
你在 Django 写的每个应用都包含一个 Python package,以特定规则保存在你的 Python 目录
中。Django 通过一个工具来自动生成 app 应用的基本目录,所以你可以专心编写代码而不
用担心如何创建目录。
•
??目(project)与应用(app)
项目可以包含多个应用,一个应用可存在于多个项目中。应用,可以是 blog 系
统,公共记录数据库,或是一个简单的投票系统等等。
在这个教程中,我们将在 mysite 中创建简单的投票 poll 应用。结果这个应用被绑定在项目
中,也就是通过 引用投票应用。在后面的教程中,我们会讨论如何包装发布这
个应用。
为了创建名为 polls 的应用,确定在 mysite 的目录中,输入命令:
python startapp polls
这会创建一个名为 polls 的目录包含应用基本文件,其中包括:
polls/
__init__.py
我们通过修改 文件,来新建两个模型:Poll 和 Choice。模型 Poll 包含问题和发
布时间。模型 Choice 包含选择文本和投票数;且每个选择被指定到一个投票上。事实上,
即新建两个 Python 类。修改 文件为如下代码所示:
from import models
class Poll():
question = eld(max_length=200)
pub_date = meField('date published')
class Choice():
poll = nKey(Poll)
choice = eld(max_length=200)
votes = rField()
注:在 Django 0.96 之前的版本中,max_length 应改为 maxlength。
代码很直观。每个模型即是一个类,是 的子类。每个模型有不同数
量的类变量,每个变量对应一个数据库字段。
每个字段是 Field 类的一个实例,比如,CharField 是字符字段,而 DateTimeField 是日期时
间字段。这会告诉 Django 每个字段的类型。
每个字段实例的名称,比如 question 和 pub_date,也将是数据库中列的名称。
一些字段类需要参数。CharField,比如,就需要参数 max_length。这不仅应用在数据库表
中,也是一个输入数据时验证条件。
最后,ForeignKey 表示数据库表的关系。这告诉 Django 每个 Choice 对应一个
Poll。Django 支持所有普遍的数据库关系:多对一、多对多和一对一关系。
激活模型
这么简短的模型代码告诉 Django 很多信息。有了它,Django 可以:
•
•
为这个应用创建数据库表;
创建 Python 数据库操作的 API,来调用 Poll 和 Choice 对象。
但是首先,我们需要告诉项目 polls 应用已被安装。
•
哲学
Django 的 app 是可插拔的:你可以将同一 app 应用在多个项目中,你也可以发
布 app 为他人使用,因为 app 不必绑定至已有 Django 安装。
再次编辑 文件,在 INSTALLED_APPS 中添加 ,如下所示:
INSTALLED_APPS = (
'',
'ttypes',
'ns',
'',
''
)
现在 Django 已经知道 mysite 包含了 polls 应用。让我们运行另一个命令:
python sql polls
你应该会看到如下的代码(也就是 polls 对应的 SQL 语句):
BEGIN;
CREATE TABLE "polls_poll" (
"id" serial NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
"choice" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
COMMIT;
再次运行 syncdb 在数据库中创建模型表。
python syncdb
命令会搜索 INSTALLED_APPS 中还未加入数据库的应用,并生成对应的数据库
表。屏幕应会显示:
Creating table polls_poll
Creating table polls_choice
Installing index for model
写你的第一个Django应用 | 第二部分
•
•
•
•
•
•
•
•
原文地址:/en/dev/intro/tutorial02/
启用管理后台
运行开发时用服务器
登录管理后台
添加 Poll 模型至管理界面
探索管理后台
自定义管理表格
添加相关对象
第二部分紧接第一部分,继续完成投票应用,并关注 Django 的自动化管理后台。
启用管理后台
Django 管理后台默认不启用。启用管理后台,有三个步骤:
1.添加 到你的 INSTALLED_APPS 设置中。
2.运行 python syncdb 命令。因为你在 INSTALLED_APPS 中添加了新内容,
所以数据库需要更新。
3.编辑 mystie/ 文件。取消如下三行前面的 "#" 号。
from b import admin
scover()
(r'^admin/(.*)', ),
运行开发时用服务器
现在让我们运行服务器,来探索一下管理后台界面。
还记得吗?在第一部分我们说过,运行服务器我们在终端输入如下命令:
python runserver
好的,现在开启浏览器,在地址栏中输入本地域名,比如:127.0.0.1:8000/admin/ 现在
你应该可以看到管理后台的登录界面:
登录管理后台
现在,试着登录。你已经在教程第一部分时创建过一个超级用户,记得吗?登录后,你应该
会看到如下界面:
你可以看到一些可编辑的内容,包括 Groups, Users 和 Sites。这是默认存在的 Django 核心
特性。
添加 Poll 模型至管理界面
还记得刚刚创建的 Poll 模型吧,这一步我们把它加入管理界面中。也就一件事要做:我们
需要告诉管理后台 Poll 模型拥有管理界面。修改 mysite/polls/ 文件,在文件最后
添加如下代码:
from import Poll
from b import admin
er(Poll)
马上刷新管理页面,就可以看到变化,无需重启服务器,服务器会自动重新载入你的项目,
所以任何改动都会立即显示在浏览器中。
探索管理后台
现在页面出现了刚刚注册的 Poll 模型,Django 知道它应该出现在管理后台首页中。
点击 "Polls",就会跳转到 poll 列表的页面,也许我们还没有任何 poll,我们可以在这里新
建一个 poll。
我们可以看到有两个标签:Question 和 Date published。比如我们在 Question 文本框中输入
What's up?;对于 Date published,我们可以点击 Today 和 Now 来规定发布日期为当前日期
和时间。
注:
•
•
•
这个表格是根据 Poll 模型自动生成的;
模型中不同的字段类型对应了不同的 HTML 输出。这个表格中就包含 CharField 和
DateTimeField 字段。
每个 DateTimeField 字段都会有 JavaScript 支持,旁边有 Today 和 Now 以及 popup
窗口方便选择日期和时间。
编辑好这个 Poll 之后,点 Save and continue editing 按钮,即保存和继续编辑,你会看到右
上角出现了 History 按钮,点击它可以查看这个 Poll 的修改历史记录。
自定义管理表格
先花几分钟感叹一下到此你并不需要编写的代码。当调用
er(Poll) 时,Django 会让你编辑这个对象,以及猜出如何显示它。
一般我们可以让 Django 自动猜出显示编辑模型的表格,如果你想控制它,可以这么做:删
除 er(Poll) 这行代码,用一下代码替代:
class PollAdmin(dmin):
fields = ['pub_date', 'question']
er(Poll, PollAdmin)
这里的思路是:创建一个 模型管理 对象,并将其传递给
er() 第二个参数(每当你需要修改模型的挂历页面时)。
上面的这次修改使 Date published 字段排到 Question 字段前面。
改变两个字段的显示顺序也许不是很惊奇,但是如果碰到管理表格有一堆字段,我们就可以
按照直观和习惯的顺序交换字段的显示顺序。
OK,说到一堆的字段,你也许会想把这些字段分开到两个字段区域中。我们可以修改刚才
的 PollAdmin 对象为:
class PollAdmin(dmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date']}),
]
fieldsets 中的小括号是 Python 语法中的 tuple(元组),这里有两个元素,第一个元素是字
段区域的名称,None 表示无名称。
另外,我们还可以给字段区域一
个 HTML 样式,Django 提供一个 collapse 的样式让某个字段区域默认是收起合并的。这对
于表格中一些字段并不常用的情况很适用。
class PollAdmin(dmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
添加相关对象
好了,我们有了 Poll 管理页面。而一个 Poll 应该有若干个 Choice,现在管理页面还没有显
示 Choice。有两种方法解决:第一个注册 Choice 像之前我们注册 Poll 一样。
from import Choice
er(Choice)
现在管理页面有了 Choices,添加页面如下:
在这个表格中,Poll 被表现为一个下拉菜单,包含所有的 Poll 对象(现在我们只有一个
What's up?)。在下拉菜单的后面,有个加号图标,点击它可以添加新的 Poll。
但这不是非常有效,你想如果你想添加更多的 Choice 和在今后编辑它们,这样的操作会很
麻烦。最好的方法是在 Poll 页面中,直接添加编辑其 Choice ,岂不很明了?
删除 er(Choice) 这行代码,添加 ChoiceInline 对象,并编辑
PollAdmin :
class ChoiceInline(dInline):
model = Choice
extra = 3
class PollAdmin(dmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
er(Poll, PollAdmin)
这段代码会告诉 Django:Choice 对象要直接在 Poll 管理页面下编辑。默认,提
供 3 个多余选项。
重新访问 Add Poll 页面,会看到如下页面:
尝试一下。然后考虑又一个小问题,这么多 choice 的字段占居了很长的页面,可以把两个
字段并排放置,只需修改刚才 ChoiceInline 的参数为:
class ChoiceInline(rInline):
#...
从 StackedInline 到 TabularInline,页面布局也换成了:
写你的第一个Django应用 | 第三部分
•
•
•
•
•
原文地址:/en/dev/intro/tutorial03/
哲学 Philosophy
设计你的 URL
写你的第一个 View
让你的 View 做点什么
•
•
•
•
•
•
快捷: render_to_response()
404: 页面无法找到
快捷: get_object_or_404()
使用 template 模板系统
简化 URLconfs
分离 URLconfs
第三部分紧接第二部分,继续完成投票应用,并关注创建显示页面的 views。
哲学
View 在 Django 中是页面的 type,完成一个特定的功能或有一个特定的模板。例如,在
Blog 应用中,你也许会用到如下 View:
•
•
•
•
•
•
Blog 首页 ── 显示最新文章
单篇文章页面 ── 显示单篇文章的页面
以年存档的页面 ── 显示指定年份中每月发表的文章
以月存档的页面 ── 显示指定月份中每天发表的文章
以天存档的页面 ── 显示指定某天中发表的文章
评论 动作── 处理每篇文章的评论
在我们的投票应用中,我们会用的如下四个 View:
1.
2.
3.
4.
Poll 存档页面 ── 显示最新投票
Poll 查看页面 ── 显示单个投票内容
Poll 结果页面 ── 显示指定投票的结果
投票 动作 ── 处理每个投票的选票
在 Django 中,每个 View 就是一个简单的 Python 函数。
设计你的URL
编写 View 的第一步是,设计你的 URL 结构。也就是要创建一个 Python 模块,叫
URLconf,用来使 URL 来搭配特定的 Python 代码。
当用户请求网页时,系统会查阅 ROOT_URLCONF 设置,该设置包含一个 Python 点语法的
字符串。Django 调入该模块,并查找模块级别的变量 urlpatterns,格式是:
(regular expression, Python callback function [, optional dictionary])
Django 从第一个正则表达式开始,向下查找,若请求 URL 符合某个正则表达式,则立即执
行。详细地说,如果当符合某个正则表达式时,Django 会调用 Python 回调函数,第一个参
数是 HttpRequest 对象,第二个参数是正则表达式从 URL 截取的值,第三是可选参数。
对于我们的例子来说,当你创建 mysite 项目时,自动设置了 ROOT_URLCONF 为:(在
文件中)
ROOT_URLCONF = ''
而且还自动创建了默认的 URLconf,在 mysite/。现在修改 文件为:
from ts import *
urlpatterns = patterns('',
(r'^polls/$', ''),
(r'^polls/(?P
(r'^polls/(?P
(r'^polls/(?P
)
这值得解释一下。当用户请求网站的页面时,比如页面 "/polls/23/",Django 由
ROOT_URLCONF 设置,加载 URLconf 模块,并查找 urlpatterns 变量,遍历正则表达式。
当找到正则表达式 r'^polls/(?P
,这指向的是 mysite/polls/ 的 detail() 函数,会传
递两个参数调用 details():
detail(request=
poll_id='23' 来自 (?P
View 函数;?P
因为 URL 规则是由一系列正则表达式组成,所以没有任何限制。而且可以给 URL 添加一个
累赘,比如 .php,万一你有很冷的幽默,可以这么做:
(r'^polls/$', ''),
但是,请不要这么做,有点傻。
请注意正则表达式并不搜寻 GET 和 POST 参数,或域名。例如,请求网页
/myapp/,URLconf 会搜寻 /myapp/;有如,请求页面
/myapp/?page=3,URLconf 仍会搜寻 /myapp/。
如果你想学习正则表达式,可以参阅 Wikipedia 和 Python 文档 ( 英 ) 。
最后,提及运行性能:这些正则表达式在第一次加载 URLconf 模块时编译。他们非常快。
写你的第一个View
至今,我们还没有开始写 View,只是说了一下 URLconf。现在,让我们确保 Django 在跟
随 URLconf。开启 Django 服务器。
python runserver
在浏览器中访问 localhost:8000/polls/ ,应该会得到一个预计的错误: View 没有找到。
ViewDoesNotExist at /polls/
Tried index in module . Error was: 'module' object has no
attribute 'index'
这个错误的出现说明在 mysite/polls/ 文件中还没有 index() 函数。尝试
"/polls/23/", "/polls/23/results/" 和 "/polls/23/vote/",也会出现相似错误,因为你也没有相应的
View。
到时候写第一个 View了。打开文件 mysite/polls/,并添加下面代码:
from import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll index.")
这是很简单的 View,只包含一个默认 index() 函数。在浏览器中重新载入
localhost:8000/polls/ 页面,你会看到 "Hello, world. You're at the poll index."。
接着添加下面 detail() 函数,参数多了一个 poll_id,是一个从 URL 中捕获的数字。
def detail(request, poll_id):
return HttpResponse("You're looking at poll %s." % poll_id)
现在可以访问,例如 localhost:8000/polls/34/ ,应该会出现 "You're looking at poll 34."。
让你的 View 做点什么
每个 View 负责做两件事情的其中一个:要么返回一个包含请求页面内容的 HttpResponse 对
象;要么返回一个错误,例如 Http404。其他的由你决定。
View 可以读取数据库数据,可以使用 template 模板系统,或第三方 Python template 模板系
统。它可以轻松地生成 PDF 文件,输出 XML,新建 ZIP 文件等等,使用 Python 库可以完
成几乎任何你想到的事情。
Django 所需要的就是 HttpResponse 或 一个错误。
好叻。让我们编写 index() 函数,即访问 "/polls/" 的默认页面。让其显示最新的 5 个投票
问题。
1.修改 index() 函数,调用 polls/ 模板;
2.设置模板路径,在 的 TEMPLATE_DIRS;
3.创建 polls/ 模板。
1. 修改 index() 函数
from te import Context, loader
from import Poll
from import HttpResponse
def index(request):
latest_poll_list = ().order_by('-pub_date')[:5]
t = _template('polls/')
c = Context({
'latest_poll_list': latest_poll_list,
})
return HttpResponse((c))
这段代码调用 "polls/" 模板,并传递内容给模板。内容是一个字典(dictionary)映射
模板变量名称至 Python 对象。
2. 设置模板路径
打开 文件,修改 TEMPLATE_DIRS 内容,指向模板存放的绝对路径,而不是相
对路径。模板目录可以是你硬盘的任何一个 Django 可以访问的目录,但是不要把他们放在
文件的根目录中,而且不要公开它们,为了安全的原因。
3. 创建模板
当你设置好模板目录后,再在其中新建一个 polls 目录,再在 polls 目录中新建一个
文件。上述 index() 中的代码
_template('polls/') 就调用文件
"template_directory/polls/"。
而 的代码如下:
{% if latest_poll_list %}
- {{ on }}
{% for poll in latest_poll_list %}
{% endfor %}
{% else %}
No polls are available.
{% endif %}
现在打开 localhost:8000/polls/ 会以列表形式显示投票系统问题。
快捷:render_to_reponse()
调用模板、填充内容和返回包含内容的页面是非常普遍的流程,为了简便,Django 提供了一
个 render_to_response() 的简便函数。所以 index() 函数还可以重新写成:
from uts import render_to_response
from import Poll
def index(request):
latest_poll_list = ().order_by('-pub_date')[:5]
return render_to_response('polls/', {'latest_poll_list':
latest_poll_list})
注意到,我们不再需要导入 loader, Context 和 HttpResponse。
这个 render_to_response() 函数用模板名称作为第一个参数,用字典(dictionary)作为
可选的第二个参数。它返回包含结果的 HttpResponse 对象。
404
现在我们修改一下 detail() 函数,即查看某特定投票的问题。思路是:如果投票 ID 存在,
显示投票问题;若不存在,则返回 Http404 页面无法找到的错误。
from import Http404
# ...
def detail(request, poll_id):
try:
p = (pk=poll_id)
except tExist:
raise Http404
return render_to_response('polls/', {'poll': p})
快捷:get_object_or_404()
使用 get_object_or_404() 快捷,可以修改 detail() View,
from uts import render_to_response, get_object_or_404
# ...
def detail(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/', {'poll': p})
这个 get_object_or_404() 函数用模型名称作为第一个参数,用主键数字作为另一个参
数。
使用模板系统
现在我们更新了 detail() 函数,而模板 polls/ 的代码为:
{{ on }}
- {{ }}
{% for choice in _ %}
{% endfor %}
{{ on }} 是指 Poll 模型的 question 属性。{% for %} 循环。。。
简化URLconf
花一些时间尝试 View 和模板系统。当你编辑 URLconf时,也许会注意到这里有一些冗余代
码:
urlpatterns = patterns('',
(r'^polls/$', ''),
(r'^polls/(?P
(r'^polls/(?P
(r'^polls/(?P
)
也就是说, 出现在每行中。
因为这是一个常见的情况,我们可以将 patterns() 的第一个参数设置为重复的前缀,例如:
urlpatterns = patterns('',
(r'^polls/$', 'index'),
(r'^polls/(?P
(r'^polls/(?P
(r'^polls/(?P
)
分离 URLconf
既然我们在 URLconf 这里,我们应该花一些时间把我们的 Poll 应用的 URL 从我们的
Django 项目设置中分离出来。Django 应用意味着可移植 ── 也就是说,每个应用都应该以
很小的改动就可以移植到另一个 Django 项目中。
拷贝文件 mysite/ 到 mysite/polls/。然后,修改 mysite/ 文件,移除所有关
于 poll 的 URL,输入一个 include():
(r'^polls/', include('')),
include(),参照另一个 URLconf。注意这个正则表达式结尾没有 $ 符号,但保留 / 斜线。
当 Django 遇到匹配 URL 时,它会把截取匹配部分,把以后的部分都传递给 include 的
URLconf,做进一步处理。
若用户访问 "/polls/34/",系统会:
会找到匹配的 '^polls/'
2.然后,再截取掉 "polls/",把剩余的部分 "34/",传递给 ‘’ URLconf
做处理。
现在我们已经分离了URLconf,需要修改分离出的 URLconf,删除 "polls/",最终为:
urlpatterns = patterns('',
(r'^$', 'index'),
(r'^(?P
(r'^(?P
(r'^(?P
)
在 include() 和 分离 URLconf 背后的想法是让 URL 变得简单易移植。现在既然我们的
写你的第一个Django应用 | 第四部分
•
•
•
•
原文地址:/en/dev/intro/tutorial04/
写一个简单的表单
使用通用 View:代码越少越好
待续……
第四部分紧接第三部分。
写一个简单的表单
让我们修改 poll/ 模板,添加一些
粗略解释:
•
•
•
上述模板为每个投票选项显示一个 radio 按钮,而每个按钮的值
value 都对应一个选项 ID,名称 name 为 choice。这意为,当用户
选择其中一个按钮并提交表单后,传递的数据为 choice=3。这是
HTML 的基本知识。
我们设置表单的动作 action 为 /polls/{{ }}/vote/,
方法 method 为 POST。使用 method="post" 十分重要,因为这会
提交数据值服务器端。当你建立表单并改变服务器端的数据时,使用
method="post",这不是 Django 特有的,而是 Web 开发基本知识。
r 只是有多少次 for` 循环。
现在,让我们新建一个 View 来处理提交的数据。记着在教程的第三部分,我
们建立了 Poll 应用的 URLconf,并包含这行代码:
(r'^(?P
所以我们在 mysite/polls/ 文件中添加 vote() 函数。
from uts import get_object_or_404, render_to_response
from import HttpResponseRedirect
from olvers import reverse
from import Choice, Poll
# ...
def vote(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
try:
selected_choice = _(pk=['choice'])
except (KeyError, tExist):
# Redisplay the poll voting form.
return render_to_response('polls/', {
'poll': p,
'error_message': "You didn't select a choice.",
})
else:
selected_ += 1
selected_()
# Always return an HttpResponseRedirect after successfully
dealing
# with POST data. This prevents data from being posted twice
if a
# user hits the Back button.
return
HttpResponseRedirect(reverse('s',
args=(,)))
这段代码包含一些新的知识点:
•
是一个可根据名称取回提交内容的对象。比如这个例
子中,['choice'] 返回选被选项的 ID 值,以字符串
形式传递。 的值始终是字符串。
Django 也提供 以同样的方法提取 GET 数据 -- 但是我们在这
里使用 ,确保数据只能在 POST 过程中改变。
•
•
如果 POST 数据不含 choice,那么 ['choice']
将会引出 KeyError。代码会检查 KeyError` 然后显示带有错误信息的
投票页面。
在增加 choice 计数之后,会返回 HttpResponseRedirect 对象。该对象只
有一个参数,即转向页面的 URL 地址。
请记住,在成功处理 POST 数据之后,一定要返回 HttpResponseRedirect。这
不是只针对 Django 的,而是 Web 开发的良好规则。
•
我们用 reverse() 函数,避免返回一个生硬的 URL 地址,反而会用
View 名称和含变量的 URL 地址。比如这个例子中,使用我们的
URLconf 设置,reverse() 返回字符串:
'/polls/3/results/'
... 3 是 的值。这 URL 会调用 'results' View 显示最终页面。注意,
你需要使用 View 的全称(包括前缀)。
在投票成功之后,'vote()' View 会调用
's',而 results() 函数为:
def results(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/', {'poll': p})
这有点像 detail() 的代码,唯一的不同是调用不同的模板。我们稍后会减
少这种重复代码。
模板 的代码如下:
{{ on }}
- {{ }} -- {{ }}
vote{{ |pluralize }}
{% for choice in _ %}
{% endfor %}
使用通用 View:代码越少越好
在 中会发现,detail() 和 results() 非常简单,但重复。
index() 也很相似。
这些 View 表达了一个 Web 开发普遍的情况:根据 URL 中的参数从数据库读
取记录,加载模板和返回渲染好的模板。因为这非常普遍,所以 Django 提供
了一个快捷方式,叫做 "通用 Views" 系统。
首先,打开 polls/ URLconf 文件,到现在为止,文件内容应大致如下:
from ts import *
urlpatterns = patterns('',
(r'^$', 'index'),
(r'^(?P
(r'^(?P
(r'^(?P
)
现要修改文件内容为如下代码:
from ts import *
from import Poll
info_dict = {
'queryset': (),
}
urlpatterns = patterns('',
(r'^$', '__list',
info_dict),
(r'^(?P
'__detail', info_dict),
url(r'^(?P
'__detail', dict(info_dict,
template_name='polls/'), 'poll_results'),
(r'^(?P
)
现在我们正在使用两个通用 View:object_list() 和
object_detail()。顾名思义,完成 显示一个对象列表 和 显示某个特定
对象内容。
•
•
•
queryset
object_detail()
pool_resutls
写你的第一个Django应用 | 第五部分
第五部分——自定义管理员功能
自定义admin表单
这足以让我们惊讶好几分钟,所有的代码我们都不需要写。
当我们调用er(Poll)时,Django只让你编辑这个对象并”推测“怎么把
它显示在管理页面上。
很多时候,你可能想要控制admin的样式和功能。你可以在你注册对象的时候把选项告诉
Django来实现。
让我们看一下在编辑表单中是怎样实现重新排序字段的。用下面的代码来替换.
register(Poll):
class PollAdmin(dmin):
fields = ['pub_date', 'question']
er(Poll, PollAdmin)
你将遵循这个模式——创建一个admin模型对象,然后把它传递给er
()的第二个参数——任何时候你需要修改admin的选项都是修改一个对象。上面具体的改
变是"Publication date"字段在"Question"字段的前面:
只有两个字段并不会给人留下深刻的印象,但当admin表单包含有大量字段的时候,选择
一个直观的排序方式就是一个重要的细节了。
并且,你可能想要把这些大量的表单字段分割归类为字段集:
class PollAdmin(dmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date']}),
]
er(Poll, PollAdmin)
字段集中每个tuple的第一个元素是字段集的标题。现在我们的表单看起来像这样:
你可以给每个字段集指定任意的HTML样式。Django提供有一个"collapse"样式,它让每
个具体的字段集在初始化时显示为折叠的。
当你的一个很长的表单中包含了许多不常用的字段时,这个样式就显得很实用了:
class PollAdmin(dmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
添加关联的对象
OK,我们已经有了一个Poll admin页面。但是一个Poll有多个Choice,管理页面并没
有显示Choices。
好的。
有两种方法可以解决这个问题。第一种方法是注册admin Choice,就像我们注册Poll那
样。这很容易:
from import Choice
er(Choice)
现在Django admin中的"Choices"已经可用了。这个"Add choice"看起来像这样:
在这表单中,"Poll"字段是一个选择框,包含数据库所有的poll。Django知道,外键在a
dmin中代表一个
在我们的例子中,只有poll存在外键。
还注意到"Poll"旁边的"Add Another"链接。每个包含有和其它对象构成外键关系的对象都
会有这个链接。
当你单击"Add Another"时,你会得到一组带有"Add poll"表单的窗体。
如果你在窗体中添加一个poll并点击"Save",Django把这个poll保存到数据库中并把它
作为选项动态添加到"Add choise"中。
但实际上,这是一种低效的添加Choice对象到系统中的做法。当你在创建Poll对象时,
如果你能给它直接添加Choice就更好了。让我们实现它吧。
移去注册Choice模型的register()方法调用。然后,编辑Poll的注册代码:
class ChoiceInline(dInline):
model = Choice
extra = 3
class PollAdmin(dmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
er(Poll, PollAdmin)
这些代码告诉Django:"Choice对象在Poll的admin page中编辑。默认,为3个cho
ice提供足够的字段。"
加载"Add poll"页面看看它是什么样子的:
它是这样工作的:有3个与Choice相关联的栏——在extra中指定的——每次你返回到
一个已经创建的对象的"Change"页面时,你都会得到另外3个的额外栏。
但还是有个小问题。它占据了太多的空间来显示关联对象Choice的所有输入域。对于这个
问题,Django提供一种制表的方式来显示关联的对象;
你只需要修改一下ChoiceInline的声明就行了:
class ChoiceInline(rInline):
#...
使用TabularInline (取代StackedInline), 关联的对象显得更紧凑,它是基于表的格式:
自定义admin change list
现在Poll admin页面已经很好了,让我们对"change list"页面做些优化——它用于显示
系统中所有的poll。
这是它看起来的样子:
默认,Django显示每个对象的str()。但有时候如果我们能显示个别字段的话会更有效果。
要做到这点,只需使用list_display admin选项,这是一个用于在对象的change list页
面内把字段名作为列名显示的tuple:
class PollAdmin(dmin):
# ...
list_display = ('question', 'pub_date')
Just for good measure, let's also include the was_published_today cust
om method from Tutorial 1:
class PollAdmin(dmin):
# ...
list_display = ('question', 'pub_date', 'was_published_today')
现在,poll change list页面看起来是这样:
你可以点击列头来排序这些值——除了was_published_today头外,因为排序不支持任
何方法的输出值。
还注意到was_published_today列头默认是它的方法名(使用下划线替换空格)。但你
可以通过给方法一个简短的属性描述来改变这个名:
def was_published_today(self):
return _() == ()
was_published__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的分页,检索,过滤,日期分层和列头排序都按
照你想要的效果工作了。
版权声明:本文标题:写你的第一个Python Django实例 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1711396205a591996.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论