1、。第一讲 入门1 开篇Django 是新近出来的 Rails 方式的 web 开发框架。在接触 Django 之前我接触过其它几种 Python 下的 web framework, 但感觉 Karrigell 是最容易上手的。不过 Django 从我个人的感觉上来看,它的功能更强大,社区也很活跃,高手众多,发展也是极为迅速。3Django的入门体验但 Django 呢?如果说最简单的web体验 Hello, Django! 如何写呢?决不会象 Karrigell 那样简单,只从它提供的教程来看,你无法在安装后非常 Easy 地写出一个 Hello, Django! 的例子,因为有一系列的安装和
2、准备工作要做。那么下面我把我所尝试写最简单的 Hello, Django! 的例子写出来。请注意,我测试时是在 Windows XP 环境下进行的。3.1安装python setup.py install参考文档 Django installed,一般地,Django 安装前还需要先安装 setuptools 包。可以从 PyPI 上搜到。目前最新的版本是 0.95 版,可以从 Django 的主页上面下载。如果你想从老的 0.91 迁移到最新版本,可以参阅 RemovingTheMagic 文档。安装后,建议检查 pythoninstalldir/Scripts 目录是否在你的 PATH 环
3、境中,如果不在,建议将这个目录设置到 PATH 中。因为如果你采用标准的 Python 安装方法,那么 Django 会自动在 Scripts 目录下安装 django-admin.py 程序。这样,一旦你设置了 Scripts 在 PATH 中,就可以在命令行下任何目录中执行 django-admin.py 了。3.2生成项目目录因为 Karrigell 可直接开发,因此放在哪里都可以。而 Django 是一个框架,它有特殊的配置要求,因此一般不需要手工创建目录之类的工作, Django 提供了 django-admin.py 可以做这件事。为使用 django-admin.py ,建议将
4、Python 的 Scripts 目录加入到 PATH 环境变量中去。django-admin.py startproject newtest这样就在当前目录下创建了一个 newtest 目录,进去入可以看到有四个文件:这个 newtest 将是我们以后工作的目录,许多讲解都是基于这个目录的。_init_.py 表示这是一个 Python 的包 manage.py 提供简单化的 django-admin.py 命令,特别是可以自动进行 DJANGO_SETTINGS_MODULES 和 PYTHONPATH 的处理,而没有这个命令,处理上面环境变量是件麻烦的事情 settings.py 它是d
5、jango的配置文件 uls.py url映射处理文件,Django的url映射是url对某个模块方法的映射,目前不能自动完成 在 0.91 版, django-admin.py startproject 会生成 apps 目录。但 0.95 版之后已经没有了。虽然 django-admin.py 为我们生成了许多东西, 而且这些东西在以后的开发中你都需要熟悉,但现在我们的目标是最简单的体验,就认为我们不需要知道它们都有什么用吧。项目创建好了,那么我们可以启动服务器吗? Django 为了开发方便,自带了一个用于开发的 web server。在 0.91 版,你需要至少修改一下 setting
6、s.py 中的 DATABASE_ENGINE ,如果你不改,那么 Django 会报错。在0.95版之后,不再需要设置了。3.3.1启动 web server:别急呀,还没看见 Hello, Django! 在哪里呢。是的,我只是想看一看, Django 能否启动。manage.py runserver一旦出现:Validating models.0 errors found.Starting server on port 8000 with settings module newtest.settings.Go to http:/127.0.0.1:8000/ for Django.Qui
7、t the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).说明 Django 真的启来了。在浏览器中看一下,有一个祝贺页面,说明成功了。3.3.2更改主机或端口 默认情况下, runserver 命令在 8000 端口启动开发服务器,且只监听本机连接。要想要更改服务器端口的话,可将端口作为命令行参数传入: python manage.py runserver 8080还可以改变服务器监听的 IP 地址。要和其他开发人员共享同一开发站点的话,该功能特别有用。下面的命令: python manage.py runserver 0.0.0.
8、0:8080会让 Django 监听所有网络接口,因此也就让其它电脑可连接到开发服务器了3.4增加一个helloworld的app吗?在 Django 中绝大多数应用都是以app形式存在的,但一定要加吗?其实并不一定。在 Django 中,每个app就是一个子包,真正调用时需要通过 URL Dispatch 来实现url与模块方法的映射。这是 Django 的一大特色,但也是有些麻烦的地方。不用它,你无法发布一个功能,如果在 Django 中存在一种缺省的简单映射的方式,这样我想可以大大提高 Django 的入门体验度。不过在比较大的项目中,使用 app 还是一个非常好的方式,它可将项目功能进
9、行分割,以便组织和代码的重用。因此根据 URL Dispatch 的机制,我们只要保证 Django 可以在正确的地方找到方法进行调用即可。那么我们就根本不去创建一个app了。在 newtest 目录下建一个文件 helloworld.py 内容为:from django.http import HttpResponsedef index(request): return HttpResponse(Hello, Django.)0.95 版之后对许多 Django 模块都做了简化。具体可参考: NamespaceSimplification 文档。3.5修改urls.pyfrom django
10、.conf.urls.defaults import *urlpatterns = patterns(, # Example: # (rnewtest/,include(newtest.apps.foo.urls.foo), (r$, newtest.helloworld.index), # Uncomment this for admin:#(radmin/, include(django.contrib.admin.urls),)上面的 r$ 是为了匹配空串,也就是形如: http:/localhost:8000/ 。如果这时 web server 已经启动了,那么直接刷新页面就行了。现在
11、觉得 Django 是不是简单多了,除了创建一个项目的操作,然后可能要修改两个配置文件。4结论Django 本身的确是一种松散的框架组合,它既复杂又简单。复杂是因为如果你想使用它的自动化的、高级的功能你需要学习很多的东西,而且它的教程一上来就是以这种过于完整的例子进行展示,自然会让你觉得很麻烦。不过看了我的讲解之后,是不是觉得还是挺简单的。那么我们就先以无数据库的方式进行下去,一点点地发掘 Django 的功能特性吧。第二讲 生成一个web form 做加法的简单例子1引言随着学习,我们的例子也开始复杂了,下一步我想实现一个简单的 web 加法器。界面会是这样:如何处理页面表格提交的数据,并且
12、会对 URL Dispatch 作更进一步的解释。2创建 add.py 文件我们先创建一个 add.py 文件。(由于我们还没有涉及到 Django 的模型,因此象 add.py 这样的东西叫什么呢?还是称其为 View 吧。因为在 django 中,View 是用来显示的,它代替了一般的 MVC 中的 Control 的作用,因为 Django 中不是 MVC 而是 MTV (Model Template View)from django.http import HttpResponsetext = + def index(request): if request.POST.has_key(
13、a): a = int(request.POSTa) b = int(request.POSTb) else: a = 0 b = 0 return HttpResponse(text % (a, b, a + b)请注意 action 为 /add/ ,在 Django 中链接后面一般都要有 / ,不然有可能得不到 POST 数据。有关更详细的关于常见问题可以参阅 NewbieMistakes 文档。这里只有一个 index 方法。所有在 view 中的方法第一个参数都会由 Django 传入 request 对象,它就是请求数据对象,它是由 Django 自动生成。其中有 GET 和 PO
14、ST 属性,分别保存两种不同的提交方式的数据,它们都可以象字典一样工作。更多关于 request 的内容参见 Request and response objects 文档。那么我的想法就是:进入页面后(就是上面的效果),页面上有两个输入文本框,一个是提交按钮,一个是显示结果的文本框。在两个输入文本框中输入整数,然后点击提交(=号按钮),将返回相同的页面,但结果文本框中将显示两数相加的和。两个输入文本框分别定义为 a 和 b 。这里的逻辑就是:先判断 POST 数据中是否有变量 a ,如果没有则表示是第一次进入,则 a, b 初始为 0 ,然后返回页面。如果有变量 a ,则计算结果,返回页面。
15、3修改urls.py,增加 add 的 url 映射。from django.conf.urls.defaults import *urlpatterns = patterns(, # Example: # (rtestit/, include(newtest.apps.foo.urls.foo), (r$, newtest.helloworld.index), (radd/$, newtest.add.index), # Uncomment this for admin:# (radmin/, include(django.contrib.admin.urls),)4 启动 server5
16、在浏览器测试:http:/localhost:8000/add,你会看到和我相似的界面,然后输入整数试一试。6补充说明1. 在 form 中的 method=post 。你当然可以使用 get ,但是在 Django 的设计风格中认为,使用 POST 表示要对数据进行修改,使用 GET 则只是获取。2. Django 提供了 URL Dispatch 文档,专门讲解有关 url 映射的东西。其中有一部分是关于 url 的正则表达式解析的。原本我认为象 Karrigell 中一样,定义在 form 中的变量会自动映射为方法的参数,但是我错了。方法中的参数是从 url 中通过正则表达式解析出来的,
17、或者是在 url_conf(即 urls.py 文件)中指定的。因此它与 Karrigell 一点也不一样。因此,如果你想从 POST 或 GET 数据中得到值,那么象我一样去做好了。使用 request.POST 或 request.GET 或还有一个可以“统吃”的方法 request.REQUEST ,它们是一个字典数据,使用起来也算方便。 从这里我更想了解方法中参数的使用,当然这个例子并没有,有机会再使用吧。关于正则表达式解析参数在 blog 和 rss 中用得是非常多的。第三讲 使用Template的简单例子1引言从上一例我们看到,表格的生成是直接在 index() 函数中返回的 HT
18、ML 代码,这种混合方式对于大型开发非常不好,下面我们就学习模板的使用。 Django 自带有模板系统,但你可以不使用它,只要在 return 前使用自已喜欢的模板系统进行处理,然后返回即可。但 Django 自带的模板系统有很多特点,我不做过多的说明。我只是想使用它。现在我的问题就是:我有一个通讯录数据,我想使用一个表格来显示。为了方便,我们不需要使用数据库,因此我把它存在 view 文件中。2创建 list.py#coding=utf-8from django.shortcuts import render_to_responseaddress = name:张三, address:地址一
19、, name:李四, address:地址二 def index(request): return render_to_response(list.html, address: address)我使用了汉字,并且字符的编码使用了 utf-8 ,请注意,而且以后如果不特别注明,所有的带汉字的文件,包括模板都将使用 utf-8 编码。这里使用了一个新方法是 render_to_response ,它可以直接调用模板并返回生成好的文本。它接收两个参数,第一个是模板的文件名。在 Django 0.91 中,模板文件都是以 .html 结尾的,并且使用时是不带后缀的。但 0.95 版本取消了缺省模板后缀
20、的设置,因此模板文件名必须是完整的,不再有默认后缀了。第二个参数是一个字典,这里只有一个 Key ,名字是 address ,它的值是一个字典的列表。只要注意模板所接收的就是这样的字典和包含字典的列表就行了。在0.91中 render_to_response 是在 django.core.extensions 中的,而到了 0.92 转变为 django.shortcuts 。3在 newtest 中创建 templates 目录:用来存放模板文件4修改 settings.pyTEMPLATE_DIRS = ( # Put strings here, like /home/html/djang
21、o_templates. # Always use forward slashes, even on Windows. ./templates,)如果有多个模板目录,加进去就行了。 Django 会按顺序搜索的。Django 还支持在 App 中定义一个 templates 目录。这样 Django 在启动时会检查所有安装的的 App 的 templates 目录,如果存在,则将路径的搜索放在 TEMPLATE_DIRS 之后。这样就可以很方便地管理你的模板了。5创建 templates/list.html通讯录 姓名地址 % for user in address % user.name u
22、ser.address % endfor %生成了一个两列的表格。在 Django 模板中 表示引用一个变量, % 表示代码调用。在变量引用中, Django 还支持对变量属性的访问,同时它还有一定的策略,详细的建议查看 The Django template language 文档。这里我也使用了汉字,因此它也需要使用 utf-8 编码。这里使用 for . in 的模板 Tag 处理。因此 address 需要是一个集合。在我们的 View 代码中, address 为一个 list 值。每个 list 又是一个字典。因此 user.name 和 user.address 就是将此字典中的
23、元素取出来。后面我们将了解更多的模板中的 Tag 标签的使用。且你会发现, Django 中的 Tag 很强大,可通过扩展形成庞大的 Tag 库方便模板的开发。6修改 urls.py增加了 list 的 url 映射。from django.conf.urls.defaults import *urlpatterns = patterns(, # Example: # (rtestit/, include(newtest.apps.foo.urls.foo), (r$, newtest.helloworld.index), (radd/$, newtest.add.index), (rlist
24、/$, newtest.list.index), # Uncomment this for admin:# (radmin/, include(django.contrib.admin.urls),)7启动 server:http:/127.0.0.1:8000/list,效果如这样:第四讲 生成csv格式文件并下载1引言经过前几节的学习,我想大家应该比较熟悉 Django 的大致开发流程了: 增加 view 方法 增加模板 修改 urls.py 剩下的就是挖掘 Django 提供的其它的能力。在我们还没有进入模型(model)之前还是再看一看外围的东西,再更进一步体验 Django 吧。在
25、Django 中我看到了一个生成 csv 格式的文档(Outputting CSV dynamically),非常好,它没有数据库,正好用来做演示。现在我的需求就是提供 csv 格式文件的下载。我们会在原来 list(表格) 例子基础上进行演示,步骤就是上面的流程。2修改 templates/list.html在文件最后增加:csv格式下载它将显示为一个链接,它所指向的链接将用来生成 csv 文件。3在newtest下增加 csv_test.py#coding=utf-8from django.http import HttpResponsefrom django.template impor
26、t loader, Contextaddress = (张三, 地址一), (李四, 地址二) def output(request, filename): response = HttpResponse(mimetype=text/csv) responseContent-Disposition = attachment; filename=%s.csv % filename t = loader.get_template(csv.html) c = Context(data: address,) response.write(t.render(c) return responseloade
27、r, Context 是从 django.core.template 导入的,而 0.95 为 django.template 。具体可以参考: NamespaceSimplification 文档。以后类似的地方不再详述。这里使用的东西多了一些。这里没有 render_to_response 了,而是演示了一个完整的从头进行模板解析的处理过程。为什么需要这样,因为我们需要修改 response 对象的值,而 render_to_response 封装了它使得我们无法修改。从这里我们也可以看到,在调用一个方法时, Django 会传入一个 request 对象,在返回时,你需要将内容写入 re
28、sponse ,必要时修改它的某些属性。更详细的建议你参考 django 所带的 request_response 文档,里面详细描述了两个对象的内容,并且还可以在交互环境下进行测试,学习非常方便。response 对象也是由 Django 自动维护的。具体的内容参见 Request and response objects 文档。这里 address 不再是字典的列表,而是 tuple 的列表。让人高兴的是, Django 的模板除了可以处理字典,还可以处理序列,而且可以处理序列中的元素。一会在模板定义中我们会看到。这里output() 是我们希望 Django 调用的方法,不再是 inde
29、x() 了。而且它与前面的 index() 不同,它带了一个参数。这里主要是想演示 url 的参数解析。因此你要注意,这个参数一定是放在 url 上的。它表示输出文件名。response = HttpResponse(mimetype=text/csv)responseContent-Disposition = attachment; filename=%s.csv % filename这两行是用来处理输出类型和附件的。它表明返回的是一个 csv 格式的文件。t = loader.get_template(csv.html)c = Context(data: address,)response
30、.write(t.render(c)这几行就是最原始的模板使用方法。先通过 loader 来找到需要的模板,然后生成一个 template 对象,再生成一个 Context 对象,它就是一个字典集。然后 t.render(c) 这个用来对模板和提供的变量进行合并处理,生成最终的结果。最后调用 response.write() 将内容写入。4增加 templates/csv.html% for row in data % row.0|addslashes, row.1|addslashes,% endfor %使用了一个 for 循环。这里 data 与上面的 Context 的 data 相对
31、应。因为 data 是一个列表,它的每行是一个 tuple ,因此 row.0, row.1 就是取 tuple 的第一个和第二个元素。 | 是一个过滤符,它表示将前一个的处理结果作为输入传入下一个处理。因此 Django 的模板很强大,使用起来也非常直观和方便。 addslashes 是 Django 模板内置的过滤 Tag ,它用来将结果中的特殊字符加上反斜线。同时我们注意到,每个 前后都有一个双引号,这样就保证每个字符串使用双引号引起来。然后在第一个与第二个元素之间还使用了逗号分隔。最后 endfor 在下一行,表示上面每行模板后有一个回车。Django 还允许你自定义 Tag ,在 T
32、he Django template language: For Python programmers 文档中有描述。5修改 urls.pyfrom django.conf.urls.defaults import *urlpatterns = patterns(, # Example: # (rtestit/, include(newtest.apps.foo.urls.foo), (r$, newtest.helloworld.index), (radd/$, newtest.add.index), (rlist/$, newtest.list.index), (rcsv/(?Pw+)/$
33、, newtest.csv_test.output), # Uncomment this for admin:# (radmin/, include(django.contrib.admin.urls),)增加了 csv 的 url 映射。上面的正则表达式有些复杂了,因为有参数的处理在里面。 (?Pw+) 这是一个将解析结果起名为 filename 的正则表达式,它完全符合 Python 正则表达式的用法。在最新的 Django 中,还可以简化一下: (w+) 。但这样需要你的参数是按顺序传入的,在一个方法有多个参数时一定要注意顺序。关于 url 的配置问题在 URL configuratio
34、n 文档中有说明。还记得吗?我们的链接是写成 /csv/address/ ,因此上面实际上会变成对 csv.output(filename=address) 的调用。6启动 server:看一下结果吧。点击链接,浏览器会提示你保存文件的。很简单吧。但这里面的内容其实也不少,而且许多地方都有很大的扩展空间。第五讲 session和数据库1引言现在我们就学习一下 session 吧。 session 可以翻译为“会话”,做过web的可能都知道。它就是为了实现页面间的数据交换而产生的东西,一般有一个 session_id ,它会保存在浏览器的 cookie 中,因此如果你的浏览器禁止了 cookie
35、 ,下面的试验是做不了的。在 Django 中的 session 也非常简单,它就存在于 request 对象的 session 属性中。你可以把它看成一个字典就可以了。下面我们做一个非常简单的功能:首先当用户进入某个页面,这个页面会显示一个登录页面,上面有一个文本框用来输入用户名,还有一个提交按钮用来提交数据。当用户输入用户名,然后点提交,则显示用户已经登录,并且打印出用户的姓名来,同时还提供一个“注销”按钮。然后如果用户再次进入这个页面,则显示同登录成功后的页面。如果点击注销则重新进入未登录的页面。2在newtest下创建 login.pyfrom django.http import H
36、ttpResponseRedirectfrom django.shortcuts import render_to_responsedef login(request): username = request.POST.get(username, None) if username: request.sessionusername = username username = request.session.get(username, None) if username: return render_to_response(login.html, username:username) else:
37、 return render_to_response(login.html)def logout(request): try: del request.sessionusername except KeyError: pass return HttpResponseRedirect(/login/)两个方法: login() 和 logout()。login() 用来提供初始页面、处理提供数据和判断用户是否登录。而 logout() 只是用来从 session 中删除用户名,同时将页面重定向到 login 画面。这里我仍然使用了模板,并且根据传入不同的字典来控制模板的生成。是的,因为 Djan
38、go 的模块支持条件判断,所以可以做到。在 login() 中的判断逻辑是:A. 先从 POST 中取 username (这样 username 需要由模板的 form 来提供),如果存在则加入到 session 中去。加入 session 很简单,就是一个字典的 Key 赋值。 B. 然后再从 session 中取 username ,有两种可能:一种是上一步实现的。还有一种可能是直接从以前的 session 中取出来的,它不是新产生的。而这里并没有细分这两种情况。因此这个判断其实对应两种页面请求的处理:一种是提交了用户姓名,而另一种则是处理完用户提交姓名之后,用户再次进入的情况。而用户再
39、次进入时,由于我们在前面已经将他的名字保存在 session 里面了,因此可以直接取出来。如果 session 中存在,则表示用户已经登录过,则输出 login.html 模板,同时传入了 username 字典值。而如果 session 中不存在,说明用户从来没有登录过,则输出 login.html 模板,这次不带值。 因此对于同一个 login.html 模板传入的不同值,后面我们会看到模板是如何区分的。在 logout() 中很简单。先试着删除 session ,然后重定向页面到 login 页面。这里使用了 HttpResponseRedirect 方法,它是从以前我们看到的 Http
40、Response 派生来的子类。更多的派生子类和关于 response 的内容要参考 Request and response objects 文档。3创建 templates/login.html% if not username % 用户名: % else %你已经登录了! username % endif %整个是一个 if 语句。在 Django 模板中的 if 可以象 Python 一样使用,如使用 not , and , or 。象 if not username 表示什么呢?它表示如果 username 不存在,或为空,或是假值等等。而此时我们利用了 username 不存在这种
41、判断。上面的逻辑表示,如果 username 不存在,则显示一个表单,显示用户名输入文本框。如果存在,则显示已经登录信息,同时显示用户名和注销按钮。而这个注销铵钮对应于 logout() 方法。4修改 urls.py:增加了 login 和 logout 两个url映射。from django.conf.urls.defaults import *urlpatterns = patterns(, # Example: # (rtestit/, include(newtest.apps.foo.urls.foo), (r$, newtest.helloworld.index), (radd/$,
42、 newtest.add.index), (rlist/$, newtest.list.index), (rcsv/(?Pw+)/$, newtest.csv_test.output), (rlogin/$, newtest.login.login), (rlogout/$, newtest.login.logout), # Uncomment this for admin:#(radmin/, include(django.contrib.admin.urls),)5启动 server 运行但我要说,你一定会报错。而且我的也在报错。从这一刻起,我们就要进入有数据库的环境了。因为在 djang
43、o 中 session 是存放在数据库中的。所以在这里要进行数据库的初始化了。6修改 settings.py,主要修改以下地方:DATABASE_ENGINE = sqlite3DATABASE_NAME = ./data.dbDATABASE_USER = DATABASE_PASSWORD = DATABASE_HOST = DATABASE_PORT = 这里我使用 sqlite3 。在使用数据库时,需要安装相应的数据库处理模块。对 sqlite3 只需要修改两项: DATABASE_ENGINE 和 DATABASE_NAME 。这里数据文件名我使用了相对路径,在实际情况下可能使用绝对路径为好。sqlite3 对应的是 pysqlite2 模块,从 http:/pysqlite.org/ 下载到最新版本。如果你使用utf-8,要注意缺省字符编码应为utf-8。同时对于 DATABASE_PORT 字段,Django 目前允许使用数字或字符串表示了。7初始化数据库:改了配置还不够,还要执行相应的建库、建表的操作,使用 django-admin.py 或 manage.py 都可以:manage.py syncdb它可以自动创建已经安装的 App 中,在数据库中不存在的 Model。并且会自动将表的权限赋与超级用户。并且把超级用户的创建也结