PythonWebFramework_Django_DevelopWeb

上一篇 / 下一篇  2006-07-19 12:18:07 / 天气: 晴朗 / 心情: 高兴 / 个人分类:Python

Python Web 框架,第 1 部分:使用 Django 和 Python 开发 Web 站点

Python Django Web 框架,从安装到完成 Web 站点的设计

*JV/x/|([&z&s0
本系列文章一共有两篇,本文是其中的第一篇。在这一篇文章中,我们将展示 Django 的用法,Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC)风格的 Web 应用程序框架。使用 Django,我们在几分钟之内就可以创建高品质、易维护、数据库驱动的应用程序。

G4KF#TcqT0Django 项目是一个定制框架,它源自一个在线新闻 Web 站点,于 2005 年以开源的形式被释放出来。Django 框架的核心组件有:

e"b*w)O1n X3YO n[0
  • 用于创建模型的对象关系映射
  • 为最终用户设计的完美管理界面
  • 一流的 URL 设计
  • 设计者友好的模板语言
  • 缓存系统

u kZH(hp1O\0本文是有关 Python Web 框架的由两篇文章组成的系列文章的第一篇。第二篇文章将向您介绍 TurboGears 框架。

)Nm;oP,yK1i%x0

|s8\ ?Z4r0要使用并理解本文中提供的代码,则需要安装 Python,并了解在初学者的水平上如何使用 Python。要查看是否安装了 Python 以及 Python 的版本号,可以输入python -V。Django 至少需要 2.3.5 版本的 Python,可以从 Python Web 站点上下载它(关于链接请参阅本文后面参考资料部分)。我们至少还应该顺便熟悉一下 MVC 架构。Linux宝库'Aai,UlZ/s

*r6v/N$Oi4|r KI0安装 Django

3x$JC\*P(d \&zI4z0Linux宝库4y'\u3~{d

本文使用了 Django 的开发版本,以便能够利用 Django 框架的最新改进。建议您在 0.95 版正式发布之前使用这个版本。关于最新发行版本,请参阅 Django 的 Web 站点(再次请您参阅参考资料来获得链接)。Linux宝库(|*u\-~H5X

Linux宝库X C+["J l[/vwg

按照以下步骤下载并安装 Django:

,AFj n^-F)S0Linux宝库7n+\b.u7D e+E'|


*TNY@J-R2o(E4?0清单 1. 下载并安装 Django
Oe UX_?]0

~/downloads# svn co http://code.djangoproject.com/svn/django/trunk/ django_src
~/downloads# cd django_src
~/downloads# python setup.py install
Linux宝库r5m3?PD9d(Y+k:W"z D9z
Linux宝库V X5Lc)m(lQ%N
Linux宝库u&t2Jm+dR#{
Linux宝库^+J8K1u n o1V;Y.x
Linux宝库 H,A%}c%Wj6`h

!H]i%iU0
jN4W S*T`:E0

U)p a2?/D|(?0

+p)u*i&VDu8g0Django 管理工具

9y;V.Kv6\Ys%nWn#L#k~0

7g I%ekJ0在安装 Django 之后,您现在应该已经有了可用的管理工具 django-admin.py。清单 2 给出了这个管理工具中可以使用的一些命令:Linux宝库7sD:bs9cR4M

Linux宝库9}'] F,{K1w

Linux宝库 z0E L(A:p0R#~
清单 2. 使用 Django 管理工具Linux宝库$u#E.YB adGEq

~/dev$ django-admin.py
usage: django-admin.py action [options]
actions:
  adminindex [modelmodule ...]
    Prints the admin-index template snippet for the given model
    module name(s).

  ... snip ...

  startapp [appname]
    Creates a Django app directory structure for the given app name
    in the current directory.

  startproject [projectname]
    Creates a Django project directory structure for the given
    project name in the current directory.

  validate
    Validates all installed models.

options:
  -h, --help		show this help message and exit
  --settings=SETTINGS	Python path to settings module, e.g.
			"myproject.settings.main". If this isn't
			provided, the DJANGO_SETTINGS_MODULE
			environment variable will be used.
  --pythonpath=PYTHONPATH
			Lets you manually add a directory the Python
			path, e.g. "/home/djangoprojects/myproject".

~Jt{0wf O%N0
:D2z1s+W*~3{(oP$`0p"Y0

X9Ld%]@ U0

,x.g7b#_7Rx0
Linux宝库 Me.UiBr

.Vn ]2X:Th]0Linux宝库 x;H$js$E MV

3tDn&pHm0Linux宝库5{^+dw:PM&A#S2k9[3]

Django 项目和应用程序

l9].u4@X0Linux宝库2S YvR%A _

要启动 Django 项,请使用 django-adminstartproject命令,如下所示:Linux宝库4An!K7ok

;@2i,rv$q.H0
Ph1Jg*ZZ }0清单 3. 启动项目
8p bC(|^}!NnA1Y0

~/dev$ django-admin.py startproject djproject
Linux宝库#[2i)?RX2@'S
Linux宝库`9a1|2C8c d1|Vg

iI^A3Z Ac7Q:F0上面这个命令会创建一个 djproject 目录,其中包含了运行 Django 项目所需要的基本配置文件:Linux宝库#[#^,JAB9^

Linux宝库VA;e\fq?ey!a


+}dS6|4wB0清单 4. djproject 目录的内容
ASi;ci&p0

__init__.py
manage.py
settings.py
urls.py

P^3R&a'?{#d0

^7bxdF0Linux宝库N,C wxA3K5`2u

对于这个项目来说,我们要构建一个职位公告板应用程序 “jobs”。要创建应用程序,可以使用manage.py脚本,这是一个特定于项目的 django-admin.py 脚本,其中 settings.py 文件可以自动提供:Linux宝库l]PsgA({6Jb

+G(j"nN vzX0Linux宝库't`3Kf9?
清单 5. 使用 manage.py startapp
G OP`H!Z0

~/dev$ cd djproject
~/dev/djproject$ python manage.py startapp jobs
Linux宝库#SjmpO(S

5of_;n*vnE5~jw E0Linux宝库)rM!M_S_

这将创建一个应用程序骨架,其中模型有一个 Python 模块,视图有另外一个 Python 模块。jobs 目录中包含以下文件:Linux宝库"A u B*X~ o7|

_'k4Ab8dt_&M0
+v,c z }Z8FZ,iU]-Vp0清单 6. jobs 应用程序目录中的内容
7r+{I`V*W1W0

__init__.py
models.py
views.py
Linux宝库C0z6K/s M*n|7{

2O8?c-]|0

t/C\ l` r0提供应用程序在项目中的位置纯粹是为新 Django 开发人员建立的一种惯例,并不是必需的。一旦开始在几个项目中混合使用应用程序,就可以将应用程序放到自己的命名空间中,并使用设置和主 URL 文件将它们绑定在一起。现在,请按照下面给出的步骤执行操作。

8Fg`EnQ0

4kemt?G0为了使 Django 认识到新应用程序的存在,还需要向 settings.py 文件中的 INSTALLED_APPS 添加一个条目。对于这个职位公告板应用程序来说,我们必须添加字符串djproject.jobsLinux宝库5x3[:@0P!^6L,H:K

3g;Y(d:k~#TM(C!?0
'pm3sB7J xf0清单 7. 向 settings.py 中添加一个条目
s xq b(s2?&tY0

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'djproject.jobs',
)

0]@/tcl0Y}0
\t RBcj+b0
Linux宝库ii#q.q9\Tx W ]
Linux宝库:x/[ @^u'z;f#I1_

n#wA+E#Jqy0

b-R.G:{/Y }QU0Linux宝库S4P.PkRu

3G1^a9r%};i3H e0Linux宝库hX0Z5{2u B)S

创建一个模型

G!hoM#md0Linux宝库5h f~X3Bp"h

Django 提供了自己的对象关系型数据映射组件(object-relational mapper,ORM)库,它可以通过 Python 对象接口支持动态数据库访问。这个 Python 接口非常有用,功能十分强大,但如果需要,也可以灵活地不使用这个接口,而是直接使用 SQL。

+k.{u N e&cO)y~t0

p|!m,^4uy t0ORM 目前提供了对 PostgreSQL、MySQL、SQLite 和 Microsoft® SQL 数据库的支持。

KJ l,o|$@1H0

2l4_z de0这个例子使用 SQLite 作为后台数据库。SQLite 是一个轻量级数据库,它不需要进行任何配置,自身能够以一个简单文件的形式存在于磁盘上。要使用 SQLite,可以简单地使用 setuptools 来安装 pysqlite(有关 setuptools 的更多资料,尤其是有关easy_install工具(需要单独安装)的资料,请参阅参考资料):

$U3M1b7Gu!pnW L0

!]3q#xZT;V0easy_install pysqlite

5lQt aS C0Linux宝库 U`1Y.D `

在使用这个模型之前,需要在设置文件中对数据库进行配置。SQLite 只需要指定数据库引擎和数据库名即可。

~)F } k2e'V pL0

X5n$V9_8N]JN0
.]_ E)H3Iz:y#Wz0清单 8. 在 settings.py 中配置数据库Linux宝库j,xP$nW.p{:N

DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = '/path/to/dev/djproject/database.db'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
Linux宝库%V4\l1~"Z2U%s[r0D
Linux宝库0bk"n"sYq

Linux宝库,W^&?7aL _tH*q

这个职位公告板应用程序有两种类型的对象:Location 和 Job。Location 包含 city、state(可选)和 country 字段。Job 包含 location、title、description 和 publish date 字段。Linux宝库D)VB?%a:dA

ASF9k f'w])B0Linux宝库&y+E-`&G:q&|7Z
清单 9. jobs/models.py 模块Linux宝库~g4h6[0zaLz

from django.db import models

class Location(models.Model):
    city = models.CharField(maxlength=50)
    state = models.CharField(maxlength=50, null=True, blank=True)
    country = models.CharField(maxlength=50)

    def __str__(self):
        if self.state:
            return "%s, %s, %s" % (self.city, self.state, self.country)
        else:
            return "%s, %s" % (self.city, self.country)

class Job(models.Model):
    pub_date = models.DateField()
    job_title = models.CharField(maxlength=50)
    job_description = models.TextField()
    location = models.ForeignKey(Location)

    def __str__(self):
        return "%s (%s)" % (self.job_title, self.location)

H yZfbp+?0

T*B s0r |V_0Linux宝库3V8taz)[ e;MLgk

__str__方法是 Python 中的一个特殊类,它返回对象的字符串表示。Django 在 Admin 工具中显示对象时广泛地使用了这个方法。Linux宝库c/Q!g F2]/Za9_

v#zWz kZP0要设置这个模型的模式,请返回 manage.py 的sql命令。此时模式尚未确定。

A!TO"I$`zb0

N uKBi4Y ?K+`0Linux宝库H EhL-TA\m E
清单 10. 使用 manage.py sql 命令查看数据库模式
a9I8a+Hb0

~/dev/djproject$ python manage.py sql jobs

BEGIN;
CREATE TABLE "jobs_job" (
    "id" integer NOT NULL PRIMARY KEY,
    "pub_date" date NOT NULL,
    "job_title" varchar(50) NOT NULL,
    "job_description" text NOT NULL,
    "location_id" integer NOT NULL
);
CREATE TABLE "jobs_location" (
    "id" integer NOT NULL PRIMARY KEY,
    "city" varchar(50) NOT NULL,
    "state" varchar(50) NULL,
    "country" varchar(50) NOT NULL
);
COMMIT;
Linux宝库 p@ rW&M

^LfA6bM+e0Linux宝库jq'zo J!j0D7Q BT5H

为了初始化并安装这个模型,请运行数据库命令syncdb

x/k`F#\sR0

$P,hA#Z`}0~/dev/djproject$ python manage.py syncdb

wyhA'WC7s+A(V[0Linux宝库^u8eE)L E,_XY^

注意,syncdb命令要求我们创建一个超级用户帐号。这是因为 django.contrib.auth 应用程序(提供基本的用户身份验证功能)默认情况下是在 INSTALLED_APPS 设置中提供的。超级用户名和密码用来登录将在下一节介绍的管理工具。记住,这是 Django 的超级用户,而不是系统的超级用户。Linux宝库!_9x+HIg

Linux宝库Y T(s"KK].KA?Q

Linux宝库'ia e2y D'h


+@fE EH0
Linux宝库wE)L k:t/V:Lw0p
Linux宝库"| j h8@;D7Y0oqM
Linux宝库&]w&k?TJ&D
Linux宝库nS'yb V1A

!A V#v,R!pw.C0

x&ZC!P7E1Z#U0查询集Linux宝库 YG#l5o!j&N[/m6s

Linux宝库@X*f1G{$W!W

Django 模型通过默认的 Manager 类objects来访问数据库。例如,要打印所有 Job 的列表,则应该使用objects管理器的all方法:

G9Bpx)dO8w0

Q9x`)}-Od0
.WR8RD7Mr)Tk0清单 11. 打印所有的职位
.o+j(A N#S4q/m;j0

>>> from jobs.models import Job
>>> for job in Job.objects.all():
...     print job

0yZ JzQ5B-L0C7r[$S:Igq0Linux宝库&Cw*W _x*N'^w

Linux宝库+B [;{z2n*VN.Z&V9j$UX

Manager 类还有两个过滤方法:一个是filter,另外一个是exclude。过滤方法可以接受满足某个条件的所有方法,但是排除不满足这个条件的其他方法。下面的查询应该可以给出相同的结果(“gte” 表示 “大于或等于”,而 “lt” 表示 “小于”)。

2R l ce;f0Linux宝库+Eu]A;Rh)t4|6b


e4h!d| _"ASm0清单 12. 排除和过滤职位Linux宝库Ad*gD?

>>> from jobs.models import Job
>>> from datetime import datetime
>>> q1 = Job.objects.filter(pub_date__gte=datetime(2006, 1, 1))
>>> q2 = Job.objects.exclude(pub_date__lt=datetime(2006, 1, 1))

d-z1R(S0D)~]B8K$W0

%Z$t+J ]T9]:o%G0

-|%Y]1fe*}uK)eR0filterexclude方法返回一些 QuerySet 对象,这些对象可以链接在一起,甚至可以执行连接操作。下面的q4查询会查找从 2006 年 1 月 1 日开始在俄亥俄州的 Cleveland 张贴的职位:

)c3l'{:R Gr(D0Linux宝库"Q:| K(xE2e*e

Linux宝库-[n;iyd[v"iI
清单 13. 对职位进行更多的排除和过滤Linux宝库Pa#z:nxIf ^c

>>> from jobs.models import Job
>>> from datetime import datetime
>>> q3 = Job.objects.filter(pub_date__gte=datetime(2006, 1, 1))
>>> q4 = q3.filter(location__city__exact="Cleveland",
...                location__state__exact="Ohio")
Linux宝库c:a VB V(O%u|"I
Linux宝库5[[ bMCp'~5Z

Linux宝库N*I0V6j#w&i1J

QuerySets 是惰性的,这一点非常不错。这意味着只在对数据库进行求值之后才会对它们执行查询,这会比立即执行查询的速度更快。Linux宝库[ oE `.p&Sn

2C0UI;w'lScp0这种惰性利用了 Python 的分片(slicing)功能。下面的代码并没有先请求所有的记录,然后对所需要的记录进行分片,而是在实际的查询中使用了 5 作为 OFFSET、10 作为 LIMIT,这可以极大地提高性能。Linux宝库L @s)Eyi

Linux宝库2W Kg3]#lp ];m E

Linux宝库7Kx&\ ~s
清单 14. Python 分片
y!_#P#e}J/\0

>>> from jobs.models import Job
>>> for job in Job.objects.all()[5:15]
...     print job

I[E:IP)O F5r0

l rU(V2G7ke y0Linux宝库8e;j,X7iu{C

注意:使用count方法可以确定一个 QuerySet 中有多少记录。Python 的len方法会进行全面的计算,然后统计那些以记录形式返回的行数,而count方法执行的则是真正的 SQL COUNT 操作,其速度更快。我们这样做,数据库管理员会感激我们的。Linux宝库P2G%_&l L#n2i ? E#^s

'L|I vE8qv`$JFP0Linux宝库B$i0hik)C~AX G
清单 15. 统计记录数Linux宝库Yg'E*w0G(_C,e:q D

>>> from jobs.models import Job
>>> print "Count = ", Job.objects.count()       # GOOD!
>>> print "Count = ", len(Job.objects.all())    # BAD!
Linux宝库Ct8j+bn0W%{
Linux宝库v"_ u0{p'](Q

.H&Y;SLwk]5D0有关的更多信息,请参阅参考资料部分给出的 Django “Database API reference” 的链接。Linux宝库#bYGP$~%N4I(t

%Rbcj%VM$}g(@0Linux宝库q#S$u9O1o$k^


}*i f3{+^ j ^5x+E;s0

O mTXGs3a%DI!A*l0
Linux宝库$~ V~R0\:If
Linux宝库 R3Q!A:N0xO
Linux宝库b/SM/gw|5A2j

5{F/h4Z"`,o0

@3M.t}KD0管理员工具

^8wE&_t u}0

Hf;e ?i/J2?cd0Django 的最大卖点之一是其一流的管理界面。这个工具是按照最终用户的思路设计的。它为我们的项目提供了很多数据输入工具。Linux宝库?c F-B"h:m`

Linux宝库v`P:R`o*LcY

管理工具是 Django 提供的一个应用程序。与jobs应用程序一样,在使用之前也必须进行安装。第一个步骤是将应用程序的模块(django.contrib.admin)添加到 INSTALLED_APPS 设置中:

1A8r-M#\Y_.}0Linux宝库]5U*|$C1r n7Z


U iN ^ t}0清单 16. 修改 settings.pyLinux宝库V&wI%m2Z_EK%@9Y

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'djproject.jobs',
    'django.contrib.admin',
)

z0| ]-Q:`2sS9n+E"e0

Q+gv ew*}/}0

(b:}4Y d.m3Pk&z0要让该管理工具可以通过 /admin URL 使用,只需要简单地取消项目的 urls.py 文件中提供的对应行的内容即可。下一节将详细介绍 URL 的配置。

|"`2{$j-^H2y0Linux宝库Y h.p*C Xn4dhGau]


e|7aZF3H-lr0?;^0清单 17. 使管理工具可以通过 urls.py 使用Linux宝库K:z0d'r+I"g `.G

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^admin/', include('django.contrib.admin.urls.admin')),
)

$rJ0vl*M'C2G0Linux宝库Z9p7W?`R+_ cN*W

Linux宝库 \%QM!sX^

这个管理应用程序有自己的数据库模型,但也需要进行安装。我们可以再次使用syncdb命令来完成这个过程:Linux宝库`lPT5cC

d1^K/|;b7dP)D?0python manage.py syncdbLinux宝库$e${0j{M ea

Linux宝库 [ ~ ]r~o*QNa7x

要查看这个管理工具,可以使用 Django 提供的测试服务器。Linux宝库I*nj,m}S c'T

X[3A P] ? K0Linux宝库2O3BX&i)gF!e Q%]
清单 18. 使用测试服务器来查看管理工具
3@,Cm\o6[#Br#f0

~/dev/djproject$ python manage.py runserver
Validating models...
0 errors found.

Django version 0.95 (post-magic-removal), using settings 'djproject.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).

&|"S/K{1O6N!t*m B']0

(r:u g)O:]W3K&~g]0Linux宝库 a,O;mB4mk)SiS F

现在可以使用 http://localhost:8000/admin 启动管理工具,并使用前面创建的超级用户帐号进行登录。我们注意到现在还没有可用的模块。

_i{ t2G'o"Y+f0

2Rw,J+o'r#o nqG^v0要让一个类可以通过管理工具进行访问,我们需要为其创建一个 Admin 子类。然后可以通过为这个子类添加类属性来定制如何对每个类进行管理。清单 19 展示了如何将 Location 类添加到这个管理工具中。

PM!g!l S]0Linux宝库 Z"k(IgiO#@d

Linux宝库9~3F,c z^ q
清单 19. 使用管理工具添加 Location 类Linux宝库%cn"Q(~V$S2YO

class Location(meta.Model):
    ...
    class Admin:
        list_display = ("city", "state", "country")
Linux宝库4y7g1y%IMI+K2S;}

%gD.?5A e]c%G'B0

u.Gj0gd!@0现在就可以通过管理界面来创建、更新和删除 Location 记录了。Linux宝库 R&uI$NY9\*Gk2}

Linux宝库6o+b0ue(n0l


&inn8q xk O0图 1. 使用管理工具编辑位置
,_!x M?&B0使用管理工具编辑位置
{?'LwR&F8s6\q0

#C} M"Y2Q1v v.i\0Linux宝库VF'}U9ff'F sq%XPf

可以按照list_display类的属性指定的城市、州和国家来列出记录并对它们进行排序。

*g%Sw-{ v#u I _)M0

@~*x TT/R~}J0Linux宝库;@fNBT3dC
图 2. 使用管理工具显示位置Linux宝库gSym3sf
使用管理工具显示位置Linux宝库CY)m$ymNAuG

_sAU/U$V0

WS8K&q#L0管理工具有无数用来管理每种模块类的选项。清单 20 给出了几个适用于 Job 类的例子:

Uj,PT2dw2H4]6h0Linux宝库$h?!c3|J5j9^


3b(NaJ1S0清单 20. 管理模块类的选项
4G/T1~w{8M.Y7M0

class Job(meta.Model):
    ...
    class Admin:
	list_display = ("job_title", "location", "pub_date")
	ordering = ["-pub_date"]
	search_fields = ("job_title", "job_description")
	list_filter = ("location",)

7yU6_4F)S)Mp0

~+C*YE|#s0c0Linux宝库;oM'H{ekW

根据以上设置,职位的标题、位置和发布日期都会在显示职位记录时用到。职位可以按照发布时间进行排序,最开始是最近发布的职位(减号表示降序)。用户可以按照标题和说明来查找职位,管理员可以根据位置对记录进行过滤。Linux宝库0h1Aro#Uz

q"D%?l(]cP0
WYLM'Z:].dr,kmg6`0图 3. 使用管理工具显示职位Linux宝库9N T?4xY0d-g
使用管理工具显示职位Linux宝库Z1N/ZfSP
Linux宝库5im.V7q6{$K2P2C)O7w8R


I4lX @ vlS]gj0

9~~N,j5v3n0
Linux宝库4Z,o-pRu-Nr

9J8^y{f2e4bh0Dr0Linux宝库M_+b{Qs"Um*W
Linux宝库$_+U5q!U#bmAF

:fr H5R$m6}0设计 URL 方案

3o$V(ZV1|C{(FL H0Linux宝库p-yz BRm*v

Django URL 分发系统使用了正则表达式配置模块,它可以将 URL 字符串模式映射为 Python 方法views。这个系统允许 URL 与底层代码完全脱节,从而实现最大的控制和灵活性。

h6|P;@k0Linux宝库e3f @A,a @`

urls.py 模块被创建和定义成 URL 配置的默认起点(通过 settings.py 模块中的 ROOT_URLCONF 值)。URL 配置文件的惟一要求是必须包含一个定义模式urlpatterns的对象。Linux宝库@t&ym'K\}`"N

!IYs.f["Q];{4do0这个职位公告板应用程序会在启动时打开一个索引和一个详细视图,它们可以通过以下的 URL 映射进行访问:

-b;NMLgz0
  • /jobs索引视图:显示最近的 10 个职位
  • /jobs/1详细视图:显示 ID 为 1 的职位信息
Linux宝库O^I-e8Oim2F9?

这两个视图(索引视图和详细视图)都是在这个 jobs 应用程序的 views.py 模块中实现的。在项目的 urls.py 文件中实现这种配置看起来如下所示:

H4EqV#r0U3O0

.w$q"S]F+rK\0
9l Z"W)^5r9a$lH+Z0清单 21. 在 djproject/urls.py 中实现视图的配置Linux宝库_,{q W:Rj

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^admin/', include('django.contrib.admin.urls.admin')),

    (r'^jobs/$', 'djproject.jobs.views.index'),
    (r'^jobs/(?P<job_id>\d+)/$', 'djproject.jobs.views.detail'),
)
Linux宝库oT:L^0o8A`.o,n

s(H i$F icM[)V0Linux宝库)j3}R%l2^Fd Y

注意<job_id>部分,这在后面非常重要。Linux宝库}!a#Uecv

Linux宝库s1Q1M7u0T.X0oE

最佳实践是提取出应用程序特有的 URL 模式,并将它们放入应用程序自身中。这样可以取消应用程序与项目的耦合限制,从而更好地实现重用。jobs 使用的应用程序级的 URL 配置文件如下所示:Linux宝库7ea,n$`5A7E|

-Q*D8L5TX,X o)C0Linux宝库*J9{7MF#V^ J7M
清单 22. 应用程序级的 URL 配置文件 urls.py
)o L/j7]az w0

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^$', 'djproject.jobs.views.index'),
    (r'^(?P<job_id>\d+)/$', 'djproject.jobs.views.detail'),
)
Linux宝库\[Ni4]
Linux宝库}{X2ez|9M

Linux宝库7U3_Cu4GA_FZ

由于 view 方法现在都是来自同一个模块,因此第一个参数可以使用这个模块的根名称来指定 djproject.jobs.views,Django 会使用它来查找index方法和detail方法:Linux宝库p8J[pgzO

Linux宝库G0Zk w5Y&^3w

Linux宝库-@ pt9]i!i'n?
清单 23. jobs/urls.py:查找 index 和 detail 方法Linux宝库 l7SOt"V-_4q3Sw6D

from django.conf.urls.defaults import *

urlpatterns = patterns('djproject.jobs.views',
    (r'^$', 'index'),
    (r'^(?P<object_id>\d+)/$', 'detail'),
)
Linux宝库&I9q;c#mQ4u O h

w&~@.s4E%\C#Fy&i0

F^:`:z L iw.xC0尝试上面的 jobs URL 会返回到这个项目中,因为它们是使用include函数将其作为一个整体来实现的。应用程序级的 URL 被绑定到下面的/jobs部分:

7r+ic{,v qc0

m8PG0p8h;P:|3k0
;i3U_ S(gU0y0清单 24. djproject/urls.py:将 URL 送回该项目Linux宝库Va'{_'s'sg8pF

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^admin/', include('django.contrib.admin.urls.admin')),
    (r'^jobs/', include('djproject.jobs.urls')),
)
Linux宝库S1R0jE9`)Wp/T-C1d-T

ff,`].AS K:~&^0

,G%X,|M2~ QJ d*JM0如果现在尝试使用测试服务器来访问索引页(http://localhost:8000/jobs),会得到一个错误,因为正在调用的视图(djproject.jobs.views.index)不存在。

g(j{,j6V2q~;`:Wy0Linux宝库7I4L;Idm\L0p-s


WafW0D"z!j7K SI0


-mSQ$Q#f7^ rt0

2hg?z?9G,O0

"uM2s}KT ^0
Linux宝库yv P7o9t#BFV

[ao*l!Q0Linux宝库&J8Rq3R dm y }

-|d5h#NH4wI0实现视图

Ju&r*xwsH0Linux宝库1aC6}.lGB2q-T

视图是一个简单的 Python 方法,它接受一个请求对象,负责实现:Linux宝库4l ^9A4TBy.AW-S

  • 任何业务逻辑(直接或间接)
  • 上下文字典,它包含模板数据
  • 使用一个上下文来表示模板
  • 响应对象,它将所表示的结果返回到这个框架中
Linux宝库 F*Z-D V{

在 Django 中,当一个 URL 被请求时,所调用的 Python 方法称为一个视图(view),这个视图所加载并呈现的页面称为模板(template)。由于这个原因,Django 小组将 Django 称为一个 MVT(model-view-template)框架。另一方面,TurboGears 把自己的方法称作控制器(controller),将所呈现的模板称为视图(view),因此缩写也是 MVC。其区别在于广义的语义,因为它们所实现的内容是相同的。

#V BW f.dD\J$x_"z0

%[R&G*t"d0最简单的视图可能会返回一个使用字符串初始化过的 HttpResponse 对象。创建下面的方法,并生成一个/jobsHTTP 请求,以确保 urls.py 和 views.py 文件都已经正确设置。Linux宝库#D%x$Qgx!}o%e1um |

Linux宝库5x NOQw-b;|7H1bZ

Linux宝库%O*i:x'l3} Z%S
清单 25. jobs/views.py (v1)
,z'SsIVF@U0

from django.utils.httpwrappers import HttpResponse

def index(request):
    return HttpResponse("Job Index View")

E m6t;J,t!p$Q C0

W6J#fcz1f PUJ0Linux宝库1i P?CW7u%@

下面的代码将获取最近的 10 个职位,并通过一个模板呈现出来,然后返回响应。没有下一节中的模板文件,这段代码就无法正常工作。Linux宝库+P:DU6L? MR@

Linux宝库$we d Y:r*[Nv A


/D%gH3cH h3~~0清单 26. jobs/views.py (v2)
!CL'p'h%Do9r0

from django.template import Context, loader
from django.http import HttpResponse
from jobs.models import Job

from django.template import Context, loader
from django.http import HttpResponse
from jobs.models import Job

def index(request):
    object_list = Job.objects.order_by('-pub_date')[:10]
    t = loader.get_template('jobs/job_list.html')
    c = Context({
        'object_list': object_list,
    })
    return HttpResponse(t.render(c))

r(]!LvP'u h6WV5G4a0

Az#O&?,eH0

/OD7ER]0在上面的代码中,模板是由jobs/job_list.html字符串进行命名的。该模板是使用名为object_list的职位列表的上下文呈现的。所呈现的模板字符串随后被传递到 HTTPResponse 构造器中,后者通过这个框架被发送回请求客户机那里。Linux宝库q n:u1H#NCdF4BI

Linux宝库8`0h j \ [c,T#c

加载模板、创建内容以及返回新响应对象的步骤在下面都被render_to_response方法取代了。新增内容是详细视图方法使用了一个get_object_or_404方法,通过该方法使用所提供的参数获取一个 Job 对象。如果没有找到这个对象,就会触发 404 异常。这两个方法减少了很多 Web 应用程序中的样板代码。

6R?5g C7ll|.Cw0

nZE!hA R0
sH w/UB0清单 27. jobs/views.py (v3)
-L?*m_5nY0

from django.shortcuts import get_object_or_404, render_to_response
from jobs.models import Job

def index(request):
    object_list = Job.objects.order_by('-pub_date')[:10]
    return render_to_response('jobs/job_list.html',
                              {'object_list': object_list})

def detail(request, object_id):
    job = get_object_or_404(Job, pk=object_id)
    return render_to_response('jobs/job_detail.html',
                              {'object': job})

7d{\-?TK([;j9e0

:z:sZ#Dt0

k[BSB7e.C0注意,detail使用object_id作为一个参数。这是前面提到过的 jobs urls.py 文件中/jobs/URL 路径后面的数字。它以后会作为主键(pk)传递给get_object_or_404方法。

z]*o gj"S0

7F/d}&`(?Ko0上面的视图仍然会失败,因为它们所加载和呈现的模板(jobs/job_list.html and jobs/job_detail.html)不存在。Linux宝库$Y h3cik,J3v1t)c4p

Linux宝库Z? ^ys"LR


!H1\!H X$w1d9cX0


#T_*c5G1Zb7D0
Linux宝库$j6R$V9Z+b+j[
Linux宝库|` P1lc-N2U)_'U2Z

m'U2l0wU0
(^9~;Zx@1I1I$k3n*n0

8hJR"{t@?Z0

*WL2U CI6N0创建模板

#t n&Y'PYb0

&G|H)Ok}0F0Django 提供了一种模板语言,该语言被设计为能够快速呈现且易于使用。Django 模板是利用{{ variables }}{% tags %}中嵌入的文本创建的。变量会使用它们表示的值进行计算和替换。标记用来实现基本的控制逻辑。模板可以用来生成任何基于文本的格式,包括 HTML、XML、CSV 和纯文本。Linux宝库 Of)K`)msW

UF7c5N3m$M0第一个步骤是定义将模板加载到什么地方。为了简便起见,我们需要在 djproject 下面创建一个 templates 目录,并将这个路径添加到 settings.py 的 TEMPLATE_DIRS 条目中:Linux宝库;Sqb/d5i,^/W)n3v(Y

Linux宝库p ~6D/mH y.BY4m

Linux宝库tU;R$E&O m-T#e,t(k
清单 28. 在 settings.py 中创建一个 templates 目录Linux宝库#Z l4p O-I+Zd-M e[2W

TEMPLATE_DIRS = (
    '/path/to/devdir/djproject/templates/',
)

h8HF&Z4TJEk'|0Linux宝库x b2p0R6^ gI

n0m!~7yP&k&n!Ia0Django 模板支持称为模板继承(template inheritance)的概念,它允许站点设计人员创建一个统一的外表,而不用替换每个模板的内容。我们可以通过使用块标记定义骨干文档或基础文档来使用继承。这些块标记都是使用一些包含内容的页面模板来填充的。这个例子给出了一个包含称为titleextraheadcontent的块的 HTML 骨干:Linux宝库L.g|1c8u

Linux宝库8J5~A0igv


4Z!M!K+j7O/L0清单 29. 骨干文档 templates/base.htmlLinux宝库J,v/T g*Ht n1Sq

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Company Site: {% block title %}Page{% endblock %}</title>
    {% block extrahead %}{% endblock %}
  </head>
  <body>
    {% block content %}{% endblock %}
  </body>
</html>

@uL k0G#D0

o:W)x+`'el0Linux宝库M0X-n gs(Mk

为了取消应用程序与项目之间的耦合,我们使用了一个中间基本文件作为 Job 应用程序所有页面文件的基础。对于这个例子来说,为了简便起见,我们将应用程序的 CSS 放到这个基本文件中。在实际的应用程序中,需要有一个正确配置的 Web 服务器,将这个 CSS 提取出来,并将其放到 Web 服务器所服务的静态文件中。Linux宝库} f`U's8A

Linux宝库#h,X~g#s\{


(b5c/N#I;QJGS0清单 30. 中间基础文件 templates/jobs/base.htmlLinux宝库h1T,Xh U0e[G`

{% extends "base.html" %}

{% block extrahead %}
    <style>
        body {
            font-style: arial;
        }
        h1 {
            text-align: center;
        }
        .job .title {
            font-size: 120%;
            font-weight: bold;
        }
        .job .posted {
            font-style: italic;
        }
    </style>
{% endblock %}

2i*irH K%v B0Linux宝库5{_"I5Ys

Linux宝库$qk;yT!J,LL4s6\u"v

默认情况下,Django 测试服务器并不会为静态文件提供服务,因为这是 Web 服务器的工作。但是在开发过程中,如果您希望 Django 可以提供图像、样式表等,那么请参阅参考资料中有关如何激活这个特性的链接。

)D1oO!JEI0

_&H9P(l+DYX0现在我们要创建视图所加载并呈现的两个页面模板。jobs/job_list.html模板简单地循环遍历object_list,它通过索引视图遍历其内容,并显示一个到每条记录的详细页面的链接。Linux宝库&{R.g,z_$W

~ f Mg@.\0
o#qI3Ie {f9s0清单 31. templates/jobs/job_list.html 模板Linux宝库(S.L)IhZAIO.yg

{% extends "jobs/base.html" %}

{% block title %}Job List{% endblock %}

{% block content %}
    <h1>Job List</h1>
    <ul>
    {% for job in object_list %}
        <li><a href="{{ job.id }}">{{ job.job_title }}</a></li>
    {% endfor %}
    </ul>
{% endblock %}

z |\;L0Z:A @0

-j1r7ks,h:}h.\-Z0

Z9c5?$AB0jobs/job_detail.html页面会显示一条称为job的记录:

7mW"d6te:sN0

D*vXV&x"f:]-o0Linux宝库!D J JDy:ILnm
清单 32. templates/jobs/job_detail.html 页面Linux宝库#nqr\9C(D

{% extends "jobs/base" %}

{% block title %}Job Detail{% endblock %}

{% block content %}
    <h1>Job Detail</h1>

    <div class="job">
        <div class="title">
            {{ job.job_title }}
            -
            {{ job.location }}
        </div>
        <div class="posted">
            Posted: {{ job.pub_date|date:"d-M-Y" }}
        </div>
        <div class="description">
            {{ job.job_description }}
        </div>
    </div>
{% endblock %}

i'\$ojeR&W0b0Linux宝库e*P&{'`pLR

Linux宝库d S4`J p

Django 模板语言已经被设计为只能实现有限的功能。这种限制可以为非程序员保持模板的简单性,同时还可以让程序员不会将业务逻辑放到不属于自己的地方,即表示层。请参阅参考资料中模板语言文档的链接。

zf#^~ ^x"kh0s0

i`&K`M B'J0
"j4Ful1T5W1a0

Linux宝库g:rk(jCKpUF1s

.p)~;{4L ? dlC8V:z'g-@0

$wD;qkI.of0
Linux宝库qY%S*LKB

+w1F*?-CrfHvLc0

$vx'g0s!N.S|$Hi6K0Linux宝库;u9c.bXd+W(n

通用视图

*^2A1ie Z.]C:W irDb0

3F4SC~ m+}W:K(O9H0Django 提供了 4 种通用视图(generic view),它们可以让开发人员创建遵循典型模式的应用程序:Linux宝库jp.K$Z`K+_

  • 页面列表/详细页面(与上面的例子类似)
  • 基于数据的记录分类(对于新闻或 blog 站点非常有用)
  • 对象的创建、更新和删除(CRUD)
  • 简单直接的模板表示或简单地对 HTTP 重新进行定向
Linux宝库4hOw#I0n3`

我们没有创建样板视图方法,而是将所有的业务逻辑都放入了 urls.py 文件中,它们都由 Django 提供的通用视图进行处理。

`)h I4F D\$J0Linux宝库qL0c7|?(^E?T


[s9YX2x q&\T#ZG0清单 33. jobs/urls.py 中的通用视图
DV BJ(N,f0

from django.conf.urls.defaults import *
from jobs.models import Job

info_dict = {
    'queryset': Job.objects.all(),
}

urlpatterns = patterns('django.views.generic.list_detail',
    (r'^$', 'object_list', info_dict),
    (r'^(?P<object_id>\d+)/$', 'object_detail', info_dict),
)
Linux宝库`,? PC!I/pN
Linux宝库5jou/j m5pOn5E

*N/iysCp#@0这个 urls.py 文件中的 3 个主要变化如下:Linux宝库#z~9s]1} F}1o^

  • info_dict映射对象会为要访问的 Job 提供一个查询集。
  • 它使用了django.views.generic.list_detail,而不是djproject.jobs.views
  • 真正的视图调用是object_listobject_detail

*H.hE }&Z.R0zO0这个项目需要遵循一些要求才能让通用视图自动工作:Linux宝库*Z VO/aK1I!qUF

  • 通用详细视图期望获得一个object_id参数。
  • 模板遵循下面的命名模式:app_label/model_name_list.html (jobs/job_list.html)app_label/model_name_detail.html (jobs/job_detail.html)
  • 列表模板处理一个名为object_list的列表。
  • 详细模板处理一个名为object的对象。
Linux宝库.z `{}#m/a;V V

更多选项可以通过info_dict来传递,其中包括指定每个页面中对象个数的paginate_by值。

}hfFNBO1t0

FD"\q1Vc he o0
#]zQd*c1DW,A0

Linux宝库-n'H3y dk6Zk

Zq? ]V-\I { q0

H5i:u,^1Cy ?0
Linux宝库'q"Ri\]3AC%E)]

F~Af;S6ISI/k0

e ?@#K(v&c;U-g&d0Linux宝库| f _uS;F

结束语

m%T)R S:q0g0

ur8[5Kt*O)s0本系列的下一篇文章将介绍 TurboGears,这是另外一个 Python Web 框架;并且会将该框架与 Django 进行比较。Linux宝库T%Ua"rl


TAG: 电脑网络 Python

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

数据统计

  • 访问量: 20395
  • 日志数: 30
  • 建立时间: 2006-07-08
  • 更新时间: 2006-08-30

RSS订阅

Open Toolbar