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/(?Pd+)/$', ''),

(r'^polls/(?Pd+)/results/$', 's'),

(r'^polls/(?Pd+)/vote/$', ''),

)

这值得解释一下。当用户请求网站的页面时,比如页面 "/polls/23/",Django 由

ROOT_URLCONF 设置,加载 URLconf 模块,并查找 urlpatterns 变量,遍历正则表达式。

当找到正则表达式 r'^polls/(?Pd+)/$' 就会加载

,这指向的是 mysite/polls/ 的 detail() 函数,会传

递两个参数调用 details():

detail(request=, poll_id='23')

poll_id='23' 来自 (?Pd+)。在正则表达式中,小括号之间的值会传递给

View 函数;?P 定义了传递参数的名称;而 d+ 是匹配一个序列数字。

因为 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 %}

    {% for poll in latest_poll_list %}

  • {{ on }}
  • {% 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/(?Pd+)/$', ''),

(r'^polls/(?Pd+)/results/$', 's'),

(r'^polls/(?Pd+)/vote/$', ''),

)

也就是说, 出现在每行中。

因为这是一个常见的情况,我们可以将 patterns() 的第一个参数设置为重复的前缀,例如:

urlpatterns = patterns('',

(r'^polls/$', 'index'),

(r'^polls/(?Pd+)/$', 'detail'),

(r'^polls/(?Pd+)/results/$', 'results'),

(r'^polls/(?Pd+)/vote/$', 'vote'),

)

分离 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'^(?Pd+)/$', 'detail'),

(r'^(?Pd+)/results/$', 'results'),

(r'^(?Pd+)/vote/$', 'vote'),

)

在 include() 和 分离 URLconf 背后的想法是让 URL 变得简单易移植。现在既然我们的

写你的第一个Django应用 | 第四部分

原文地址:/en/dev/intro/tutorial04/

写一个简单的表单

使用通用 View:代码越少越好

待续……

第四部分紧接第三部分。

写一个简单的表单

让我们修改 poll/ 模板,添加一些

标记。

{{ on }}

{% if error_message %}

{{ error_message }}

{%

endif %}

{% for choice in _ %}

id="choice{{ r }}" value="

{{ }}" />

for="choice{{ r }}">{{ }}

{% endfor %}

粗略解释:

上述模板为每个投票选项显示一个 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'^(?Pd+)/vote/$', ''),

所以我们在 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 }}

    {% for choice in _ %}

  • {{ }} -- {{ }}

    vote{{ |pluralize }}

  • {% endfor %}

使用通用 View:代码越少越好

在 中会发现,detail() 和 results() 非常简单,但重复。

index() 也很相似。

这些 View 表达了一个 Web 开发普遍的情况:根据 URL 中的参数从数据库读

取记录,加载模板和返回渲染好的模板。因为这非常普遍,所以 Django 提供

了一个快捷方式,叫做 "通用 Views" 系统。

首先,打开 polls/ URLconf 文件,到现在为止,文件内容应大致如下:

from ts import *

urlpatterns = patterns('',

(r'^$', 'index'),

(r'^(?Pd+)/$', 'detail'),

(r'^(?Pd+)/results/$', 'results'),

(r'^(?Pd+)/vote/$', 'vote'),

)

现要修改文件内容为如下代码:

from ts import *

from import Poll

info_dict = {

'queryset': (),

}

urlpatterns = patterns('',

(r'^$', '__list',

info_dict),

(r'^(?Pd+)/$',

'__detail', info_dict),

url(r'^(?Pd+)/results/$',

'__detail', dict(info_dict,

template_name='polls/'), 'poll_results'),

(r'^(?Pd+)/vote/$', ''),

)

现在我们正在使用两个通用 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中代表一个