Python的Django框架使用入门指引
前言
传统 web 开发方式常常需要编写繁琐乏味的重复性代码,不仅页面表现与逻辑实现的代码混杂在一起,而且代码编写效率不高。对于开发者来说,选择一个功能强大并且操作简洁的开发框架来辅助完成繁杂的编码工作,将会对开发效率的提升起到很大帮助。幸运的是,这样的开发框架并不少见,需要做的仅是从中选出恰恰为开发者量身打造的那款web框架。
自从基于 mvc 分层结构的 web 设计理念普及以来,选择适合的开发框架无疑是项目成功的关键性因素。无论是 struts、spring 或是其他 web 框架的出现,目的都是为帮助开发者把所有的编码工作打理的井井有条、赏心悦目。在动态语言领域,python、ruby、groovy 等语言在 web 开发中也逐渐发展壮大,掀起一浪接一浪的开发热潮。面对 ruby on rails 渐渐深入人心的宣传攻势和火热势头,更为成熟且不乏优秀程序员的python 社区也纷纷推出欲与之抗衡的web开发框架。在对 python 旗下的开发框架经过一番取舍比较之后,笔者选择了 python 框架 django 作为 web 开发框架的首选,究其缘由,就是看中了 django 新颖简洁的开发模式和巨大的发展潜力。
在下面的章节里,将通过一个完整的 django 框架 web 开发示例,详细讲解开发过程中 mvc 各层次代码编写过程中所需的各种要素与资源,通过实例体验 django 为 web开发者带来的高效与便捷。
细说django
django 是应用于 web 开发的高级动态语言框架,最初起源于美国芝加哥的 python 用户组,具有新闻从业背景的 adrian holovaty 是 django 框架的主要开发者。在 adrian 的带领下,django 小组致力于为 web 开发者贡献一款高效完美的python 开发框架,并且在 bsd 开放源代码协议许可下授权给开发者*使用。
django 拥有完善的模板机制、对象关系映射机制以及用于动态创建后台管理界面的功能,利用 django,可以快速设计和开发具有 mvc 层次的 web 应用。为了打消开发者选用 django 框架时的疑虑,首先分析一下 django 引人注目的特性。在实体映射方面,django 的对象相关映射机制帮助开发者在 python 类中灵活定义数据模型,并且django 具有功能丰富的动态数据库访问 api,可以大幅度简化书写 sql 语句的繁杂工作。同时 django 支持包括 postgresql,mysql,sqlite,oracle 在内的多种后台数据库。django 的 url 分发设计的十分简洁美观,不会在链接中产生一大串杂乱且难以理解的字符。使用 django 可扩展的内置模板,可以将模型层、控制层与页面模板完全独立开来进行编码。django 还具有自己的 cache 系统,如果需要,也可以根据开发者的要求嵌套其他的 cache 框架。
起程前的准备
即使是对 python 语言还不太熟悉,django 开发的起步过程对于新手来说也并不复杂,通过使用 django 框架完成下面的 web 应用开发,可以在过程的每个步骤之中体会到 django 框架赋予开发者的敏捷与*。
在开始之前,首先要配置好python和django的开发环境,下面的示例将在windows操作系统下进行,与linux/unix操作系统环境下的开发过程相比,仅在环境变量配置等方面略有不同。目前python的最新版本是2.5.1,在官方站点python.org下载安装包后搭建好python的编译运行环境,接下来还需要把python的安装路径添加在系统环境变量path里面,以便在命令行下使用python进行编译及运行。
django目前的最新发行版本是0.96版,其压缩包可以在官方站点djangoproject.com下载。解压后进入django目录,在命令行里执行python setup.py install,这样django就会作为第三方模块被安装在python的site-packages目录中,然后把django中bin目录的路径添加到环境变量path里面,这样在命令行里就可以方便的使用django提供的各种指令。
开始django的旅程
在下面的步骤里,将会利用django框架实现一个完整小巧的web应用程序。应用实例将创建实现一个新闻公告牌,用户可以从后台添加新闻分类和条目,然后在前端页面中显示新闻的统计信息。在应用的实现过程中,将会逐步介绍django的开发方式及其带来的快捷体验。
为帮助开发者实现不同的功能,django为我们提供了众多的开发指令,大部分繁琐的操作都被django集成在简洁的命令行提示符中实现。现在打开命令提示符,进入到想要创建应用的目录后键入django-admin.py startproject news命令,调用django的控制台命令新建一个名为news的工程,与此同时django还在新创建的news文件夹下生成以下四个分工不同的文件。
1. __init__.py
文件__init__.py可以向python编译器表明当前文件夹下的内容是python工程模块。
2.manage.py
manage.py是python脚本文件,与django的命令行工具django-admin.py配合,可以对建立的工程进行管理配置。
3.settings.py
这是django工程的配置文件,与工程相关的工程模块和数据库全局配置信息都在settings.py中设置。
4.urls.py
文件urls.py负责配置url的地址映射以及管理url的地址格式。
当新的工程建立好之后,假如迫不及待就想知道新建工程的模样,django已经为你准备好一款轻量级的web服务器以便在开发过程中随时测试使用。开发者只需在命令提示符下进入工程目录,键入命令manage.py runserver,就可以启动web服务器来测试新建立的工程,如果启动没有错误,将可以看到下面这样的提示信息:“development server is running at http://127.0.0.1:8000/” 表示当前工程已经可以通过本机的8000端口访问。通过浏览器打开上述地址,如图1所示的django项目初始页面将会出现在读者面前。
图 1. django项目初始页面
在命令行里使用ctrl+break或ctrl+c的组合键可以停止runserver命令启动的web服务器。当然,django自带的web服务器一般只是在开发测试的过程中使用,当django工程真正发布时,可以通过加载mod_python.so模块把django应用部署在apache上,以方便web访问的管理和配置。
django的模型定义
在工程建立好之后,接下来就可以编写django的应用模块。键入命令python manage.py startapp article,命令会在当前工程下生成一个名为article的模块,目录下除了标识python模块的__init__.py文件,还有额外的两个文件models.py和views.py。
在传统的web的开发中,很大的一部分工作量被消耗在数据库中创建需要的数据表和设置表字段上,而django为此提供了轻量级的解决方案。借助django内部的对象关系映射机制,可以用python语言实现对数据库表中的实体进行操作,实体模型的描述需要在文件models.py中配置。
在当前的工程中,需要有两个models模型,分别对应list表和item表,用来存储新闻的分类和新闻的条目,每个item项都会有一个外键来标记文章的归属分类。下面打开django创建的models.py文件,按照文件注释中提示的模块添加位置,编写如下的代码:
清单 1. models.py文件模型定义
class list(models.model): title = models.charfield(maxlength=250, unique=true) def __str__(self): return self.title class meta: ordering = ['title'] class admin: pass
上面这段python代码定义了存储新闻分类的list数据表,上述模型中的定义会被django转换成与数据库直接交互的结构化查询语言来建立数据表,即创建一个名为list的表格,表格内的两个字段分别是django自动生成的整型主键id和最大宽度为250个字符的varchar类型字段title,并且在title字段上定义了唯一性约束,来保证新闻分类不会有完全相同的名称。
在list类文件里还定义了函数__str__(),作用是返回self字符串表示的title字段。而在类meta中,设置了list表格按照title字母顺序的排序方式。在类admin的设置中,允许django针对当前的models模型自动生成django超级用户的后台管理入口,关键词pass设定django将按照默认方式生成后台管理界面。这一部分在稍后的章节可以看到,由此也可以体会到django带来的独特魅力。下面再来添加新闻条目item对应的models模型,代码如下面所示:
清单 2. 添加新闻条目models模型
import datetime class item(models.model): title = models.charfield(maxlength=250) created_date = models.datetimefield(default=datetime.datetime.now) completed = models.booleanfield(default=false) article_list = models.foreignkey(list) def __str__(self): return self.title class meta: ordering = ['-created_date', 'title'] class admin: pass
item数据表对应的models代码稍微复杂一些,但并不晦涩。代码里首先引入datetime类型,用于定义表示文章创建日期的created_date字段,并且通过python的标准函数datetime.datetime.now返回系统当前日期来设置字段的默认值。在记录排序的ordering设置中,符号“-”表示按照日期的倒序进行排列,如果文章创建日期相同,则再按照title的字母序正序排列。
到此为止,应用中模型部分需要定义的两个数据表都已经创建完毕,下一步的工作是让django部署并在数据库中生成已经写好的models模型。
django模块的部署
在django中,与工程全局相关的设置都需要在配置文件settings.py中添加。笔者使用mysql作为后台数据库,并且已经在mysql中创建名为django_news的数据库。则需要在settings.py文件中的相应位置设定database_engine = "mysql" 以及 database_name = "django_news"。
这里要注意的是,如果使用sqlite数据库,django可以根据数据库的名称自动在sqlite中创建新的数据库,而在mysql、postgresql或其他的数据库中,则需要先创建与设定名称对应的数据库。在使用mysql数据库时,需要额外安装mysql的python链接库mysqldb-1.2.1,这个模块可以在站点http://sourceforge.net/projects/mysql-python/下载,目前支持的python版本为2.4,所以使用mysql数据库需要在2.4版本的python环境来开发运行。
接下来的database_user和database_password两项内容则需要用户根据本机设置填写访问数据库的用户名和密码。如果数据库安装在其他机器上或者更改了数据库的监听端口,则还需要设置database_host地址和database_port项。笔者使用的mysql数据库设置为:
database_user = 'django' database_password = 'django_password'
为了使django识别开发者添加的应用模块,在settings.py文件的installed_apps部分中,需要定义django工程加载的应用列表。默认情况下,列表中已经添加了django工程运行所需的部分自带模块,我们还需要把刚才编写好的应用模块news.article加入其中,同时添加django自带的django.contrib.admin应用模块,修改好的代码如下所示:
清单 3. 添加所需的模块
installed_apps = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.admin', 'news.article', )
添加admin模块后还不能立即使用django的admin后台管理界面,需要打开news工程根目录下的urls.py文件,将“# uncomment this for admin:”后面的#注释去掉,使得django针对管理界面的url转向“(r'^admin/', include('django.contrib.admin.urls')),”可用,这样访问admin模块时django就可以顺利解析访问地址并转向后台管理界面。
当配置文件的改动完成之后,就可以在news工程的命令提示符下执行manage.py syncdb指令。django会根据模型的定义自动完成orm的数据库映射工作,屏蔽了底层数据库细节和sql查询的编写。
展示django魅力的时刻已经来临,django框架将让开发者开始神奇的体验。随着命令执行后的滚动提示,django已经根据我们刚才在models里定义的映射文件,自动在数据库里创建好对应的表和字段。命令执行的同时会提示用户创建“superuser"账户,来登陆django自动创建好的后台管理界面对模型进行管理。指令执行时同步更新数据库表的命令提示如图2所示:
图 2. django指令执行时同步更新数据库表
维持学习动力的最好方式就是随时都可以找到一点小小的成就感,下面来看一下这些步骤完成了哪些工作。再次使用命令manage.py runserver来启动django自带的web服务器后,在浏览器中访问地址http://127.0.0.1:8000/admin/,使用刚才创建的superuser用户的账号和密码登陆,如图3所示漂亮的django后台管理界面就出现在眼前。
图 3. django根据模型自动生成的后台管理界面
在admin管理界面中,显示了应用中已经定义的各个models模块,当点击查看时,则会显示models中存在的数据库对象列表。django提供的后台管理界面方便用户直接更改或添加数据库字段,下面我们点击"lists"项旁边的“add”来添加新的新闻分类。在title字段中键入“sports news”或其他你喜欢的分类后保存。然后在"items"项中点击“add”,填入新闻的第一个条目,每个item条目都对应list中的一个分类项,添加item的界面如图4所示,由于设置了表之间的关联,django的item管理界面中会为已添加list分类自动生成内容的下拉选项。
图 4. 添加新闻条目的界面
django便捷的后台管理界面为web开发人员节省了大量的时间,目前使用到的只是django默认的后台管理方式,开发者还可以参考django提供的用户手册对后台进行进一步的定制和个性化。
实现django的控制层和表现层
进行到这里,django工程中的模型层已经处理完成,下面要做的就是如何用代码来与models中定义的字段进行交互,这就是django中的view部分。与传统mvc分层定义略有不同的是,在django中,view的功能是对页面请求进行响应和逻辑控制,而页面内容的表示则由django的template模板来完成。我们可以把django的view理解为实现各种功能的python函数,view负责接受url配置文件urls.py中定义的url转发并响应处理,当django收到请求之后调用相应的view函数来完成功能,article模块中的views.py文件代码定义如下:
清单 4. views.py代码定义
from django.shortcuts import render_to_response from news.article.models import list def news_report(request): article_listing = [] for article_list in list.objects.all(): article_dict = {} article_dict['news_object'] = article_list article_dict['item_count'] = article_list.item_set.count() article_dict['items_title'] = article_list.title article_dict['items_complete'] = article_list.item_set.filter(completed=true).count() article_dict['percent_complete'] = int(float(article_dict['items_complete']) / article_dict['item_count'] * 100) article_listing.append(article_dict) return render_to_response('news_report.html', { 'article_listing': article_listing })
这是一段简洁的python代码,让我们看看在这段代码里面django的函数做了哪些工作吧:
- list.objects.all方法返回news列表中所有的记录项,django可以根据后台数据库转换成相应的sql语句,在后台数据库中执行并返回查询结果。
- 每一条article文章都有item_set属性,代表news新闻条目中的每一个item项。如果需要设置查询条件,也可以使用item_set.filter方法来返回符合特定要求的item项。
- render_to_response函数返回浏览器指定的html页面,页面为django的template模板,负责展示被请求的页面内容。
在view部分的代码中,已经指定了页面显示模板为news_report.html。其实,在django工程中创建模板是一件非常方便的事情,下面要在article目录内创建这个模板页面,首先新建一个名为templates的文件夹,然后在这个模板目录里创建所需的news_report.html模板文件,模板的代码如下:
清单 5. news_report模板代码
<html> <head> <meta http-equiv="content-type" content="text/html" /> <title>新闻统计列表</title> </head> <body> <h1>新闻统计列表</h1> {% for list_dict in article_listing %} <ul> <li>新闻的分类: {{ list_dict.items_title }}</li> <li>新闻的数目: {{ list_dict.item_count }}</li> <li>已发布的新闻数目: {{ list_dict.items_complete }} ({{ list_dict.percent_complete }}%)</li> </ul> {% endfor %} </body> </html>
一般来说,django的模板代码和普通的html代码看上去没有太大差别,只是添加了django特定的模板标记,这些标记允许开发者为django模板添加页面逻辑,比方说将views.py中render_to_response函数返回的数据库结果集显示在页面中,django特有的标签在模板页里以“{%”作为开始并以“%}”作为结束。嵌入django模板的变量则以“{{”作为开始并以“}}”结束。
在上面的模板代码里面,用到了标记{% for news_dict in article_listing %}以及{% endfor %}。这样的标记告诉django模板处理机制循环取出news中的item项输出在页面中,在for循环内部,通过article_listing的属性得到view中对应的数据项字段的值并显示每个news项的title标题以及news中的item项数目。
当django的view和template都已经准备妥当,下面仅需要几步配置来告诉django存储工程应用的模板位置,这需要对配置文件setting.py中的template_dirs项进行设置。在本例中加入模板文件"news_report.html"的存储路径就可以让django把对view进行处理的结果集通过指定模板返回。按照本例应用的结构,template_dirs参数的内容设置为:
这里不要忘记django需要在路径的最末尾添加一个逗号。接下来仅需要设置访问article时的url转向地址就可以。打开urls.py文件,在admin后台管理的转向地址下一行添加如下语句:
在这里语段的最末尾,也需要有逗号标记段落的结束。在这里可以看到,django的url转发设计的非常简洁,在配置文件urls.py中对应于view的转发请求都由两部分组成,第一部分遵循正则表达式指定相匹配的url地址,第二部分是对应在view里面处理转发请求的函数。
完成了这些步骤,就可以在命令提示符下再次启动django服务器,看一下上述努力的成果了,在浏览器中打开链接http://127.0.0.1:8000/report/,将会看到新闻列表的返回界面。页面中显示了数据库中已添加所有新闻的分类统计信息。值得一提的是,django模板支持多层嵌套,并且每一层都可以使用div+css方式完成布局,可以方便的让站点页面遵循统一风格,看起来美观大方。
在上述整个过程中,对使用django进行web开发进行了初步的介绍。在应用中写的python代码不过几十行,比较起来其他的开发语言,django显得非常便捷实用,最后再来回顾一下django都帮助我们做了哪些工作吧:
- 通过django的对象关系映射模型建立了存储新闻分类以及新闻项的两张数据表,并用syncdb命令同步更新到数据库。
- 借助django的管理功能在应用中生成了一个漂亮实用的后台管理界面。
- 利用django函数和标签编写了view功能模块以及显示数据结果的template模板。
结束语
django开发框架的出现,让本例所有的这些工作变得简洁有序、赏心悦目。随着django开发框架的不断发展,更多新的特性将逐步被添加到框架体系中来。可以不夸张的说,django已经从ror的潜在竞争者,逐渐成长为可以与之针锋相对的python框架。如果说与ruby框架ror的差距,或许django目前最缺少的还是ror那庞大的用户群体。
如果看完这篇文章,读者打算一步一步进入django的精彩世界,可以在django官方站点www.djangoproject.com上阅读更多的开发文档、订阅google group上的django邮件讨论组,或者跟随django官方的教程指南进行学习,开始一次让思想*翱翔的旅程,相信在这个过程中收获的不仅仅是使用django开发的新奇体验。
希望有更多的读者来使用django框架,希望有更多的人来一起来关注django的发展,甚至参与到django的项目开发当中,为开源的社区贡献一份力量。期待django快速发展的明天、期待python实现的rails框架将会有绚丽的未来!
下一篇: 详细介绍Ruby中的正则表达式