对Django这个 框架 感 兴趣 好久了,却一直懒于 研究 学习 ,现在跟随官网的 教程 跑一遍,学学Django同时也 继续 学学 Python 。 在开始之前, 我们 先把Python和Django这个框架安装好。 官网: https://www.djangoproject.com/ 下载 :http://www.djangoproject. com /download/1.3/tarball/ 由于兼容性 问题 ,Django并不支持Python3+,只支持版本2.4到2.7,所以如果你的 系统 (本人使用的是SUSE Linux Enterprise Server 10 SP3,以下都是以这个系统为例)没有安装Python,或者版本不 符合 ,那么就先要安装一个合适的版本,我使用的是2.7.2版本:
2 |
tar jxvf Python-2.7.2. tar .bz2 |
下载完后运行python setup.py install进行安装:
2 |
tar xzvf Django-1.3. tar .gz |
4 |
python setup.py install |
安装完成后, 验证 下是否 成功 , 输入 python进入命令行,然后输入如下语句导入django并且输出django的版本号:
2 |
>>> print django.get_version() |
OK,下面我们 可以 正式开始了。 在这个教程里,我们会创建一个简单的投票 应用 。它包括两部分:
- 一个公共网页让人查看投票和进行投票。
- 一个管理网页让你添加,修改和删除投票
获取帮助:
如果你对这个教程有任何疑问,请到django-users留言或者在irc.freenode.net上访问#django,找一些可能为你提供帮助的Django用户。
下面开始 建立 一个项目。首先 cd 到存放项目的目录,然后运行 django-admin.py startproject mysite 命令创建项目:
2 |
django-admin.py startproject mysite |
执行 完后将会在当前目录创建一个名为mysite的项目。
发布包的文件名可能不同
如果你是通过Linux发布包管理系统(例如apt-get或者yum)安装Django,django-admin.py可能会被重命名为django-admin,你可以忽略命令里的.py继续完成这个文档。
Mac OS X权限问题
如果你使用的是Mac OS X,当运行django-admin.py startproject的时候可能会看到信息"permission denied"。这是因为像OS X这种基于Unix的系统,一个文件在运行前必须是"executable"的。你可以打开Terminal.app并且去到django-admin.py被安装到的目录,并运行命令chmod +x django-admin.py来解决这个问题。
注意
要避免跟Python和Django组件的命名冲突,避免使用像django和test这样的命名。
如果你是通过 python setup.py 安装Django的话,django-admin.py应该会在你的系统 路径 下。如果它不在这个路径上的话,你可以在 site-packages/django/bin 里找到它, site-packages 是你安装Python的目录。你可以考虑把某个路径软 链接 到django-admin.py,例如 /usr/local/bin 。
代码应该放在哪
如果你是PHP出身的话,你大概会把代码放在Web Server的根目录下(例如/var/www)。但在Django里,别这么干。把Python代码放在Web Server的根目录里并不是一个好主意,因为有被人在网页上看到代码的风险。这个不利于安全。
把你的代码放在根目录外面的地方,例如/home/mycod(我这里用的目录是/home/python)。
回到正题,startproject创建的目录结构如下:
这些文件的用途是:
- __init__.py: 一个空文件让Python知道这个目录是一个Python包。(如果你是一个Python初学者,可以看官方的Python文档了解更多关于包的内容)
- manage.py: 一个命令行工具用于跟项目的各种交互。详情查看django-admin.py和manage.py这两个文件。
- settings.py: 当前项目的设置和配置。详情可以查看Django settings。
- urls.py: 当前项目的URL定义。详情可以查看URL dispatcher。
下面启动Django development server来检查下成果。进入项目目录 mysite 运行命令 python manage.py runserver :
Django version 1.3, using settings 'mysite.settings' |
Quit the server with CONTROL-C. |
你已经启动了Django的开发 服务 器,一个用纯Python编写的轻量级Web server。我们已经把它包含在Django里,这样你就可以进行快速的开发而不需要去配置诸如 apache这样的Production服务器,除非你已经准备好要发布了。 注意不要把这个服务器当作发布环境用,它是专门在开发环境中使用的。 现在服务已经启动了,你可以在 浏览器 上访问http://127.0.0.1:8000/。你将会看到欢迎 页面 ,如下图:
改变端口
runserver命令的默认端口是8000。
如果你想改变端口,你可以把它作为参数传给命令行,例如,这个命令会在端口8080上启动服务:
python manage.py runserver 8080 |
如果想改变IP,那么可以跟端口一起传给命令行。如果要监听所有的公共IP,可以这样:
python manage.py runserver 0.0.0.0:8000 |
开发服务器的文档可以在runserver里找到。
现在, 编辑 settings.py 文件。修改DATABASES的 default 项里下面的值:
- ENGINE:django.db.backends.postgresql_psycopg2或者django.db.backends.mysql和django.db.backends.sqlite3。也支持其他数据库。
- NAME:数据库名。如果使用的是SQLite的话,数据库则是系统里的一个文件,所以NAME应该设为包含这个文件名字的绝对路径(注意路径要使用斜杠/,无论在什么系统上)。这个文件不需要创建,在第一次进行数据库同步的时候会自动创建这个文件。
- USER:用户名。使用SQLite的话则不需要。
- PASSWORD:密码。使用SQLite的话则不需要。
- HOST:主机地址。使用SQLite的话则不需要。如果数据库安装在同一台机器上,也可以不指定。
如果你对数据库不太熟悉的话, 建议 你使用SQLite(把 ENGINE 设为 django.db.backends.sqlite3 )。SQLite已经作为Python 2.5以上版本的一部分包含在里面,所以你不需要作任何的安装。 在编辑 settings.py 的时候,你会注意到文件底部的INSTAL LED _APPS配置项。这些变量保存了那些随着Django实例启动的Django应用(以下用app表示)的名字。app可以被使用到多个项目里,你也可以把它们打包和发布出去供其他人使用。 INSTALLED_APPS默认包含了以下app,这些app全部由Django自带:
- django.contrib.auth -- 一个认证系统。
- django.contrib.contenttypes -- 内容类型框架。
- django.contrib.sessions -- session框架。
- django.contrib.sites -- 多网站管理框架。
- django.contrib.messages -- 消息管理框架。
- django.contrib.staticfiles -- 静态文件管理框架。
为了方便使用,这些通常 网站 都会用到的应用已经默认包含在项目里。 这些app每个都至少要用到一个以上的数据库表,所以在使用这些应用前我们先要创建这些表。运行一下命令:
syncdb命令会根据 settings.py 文件里的INSTALLED_APPS设置创建必需的数据表。你会看到创建表的信息以及会提示你为认证系统创建超级用户,跟着提示做就行了。
简化
就像我们上面说的,基于常理,默认的那些应用会被自动包含,但是并不是所有人都会用到它们。所以如果你不需要用到这些应用,你可以在执行syncdb命令前随意把它们在INSTALLED_APPS里注释掉或者删掉。syncdb只会为INSTALLED_APPS里的应用创建表。
创建模型
现在环境已经搭好了,可以正式开工了。 在Django里,你写的每个应用都包含一个Python的包,这个包会根据一个特定的约定放在Python path里。Django会自动为每个app创建一些 基本 的目录结构,所以你可以专心写代码而不必在创建目录上费心。
Projects vs. apps
项目跟app有什么不同呢?app是一个实现某个功能的网页应用,例如一个网页日志系统,一个公共数据数据库或者一个简单的投票应用。而一个项目则是由一堆配置和应用组成的网页。一个项目可以包含多个应用,而一个应用可以使用在多个项目里。
你的应用可以存放在Python path上的任何地方。简单起见,我们在 mysite 目录里创建一个投票应用。确认你的当前目录为 mysite ,并输入命令:
python manage.py startapp polls |
这样会创建一个目录polls,如下:
这个目录结构将会存放这个poll应用。 在Django里写一个有数据库操作的网页应用第一步要做的就是定义模型(Model),模型实质上就是附带元数据的数据层(database layout)。
原理(Philosophy)
模型是跟你的数据相关的一个单一和明确的数据源。它包含了你所储存的数据的一些必要字段和行为。Django遵循DRY原则,目的是在一个地方定义你的数据模型然后根据它自动派生出其他的东西。
在我们这个简单的投票应用里,我们创建了两个模型:polls和choices。一个poll包含有一个问题和一个发表日期。一个choice有两个字段:选项 文字 和投票计数。每一个choice都跟一个poll关联。 这个概念将由一个简单的Python类来实现。编辑文件 polls/models.py :
1 |
from django.db import models |
2 |
class Poll(models.Model): |
3 |
question = models.CharField(max_length = 200 ) |
4 |
pub_date = models.DateTimeField( 'date published' ) |
5 |
class Choice(models.Model): |
6 |
poll = models.ForeignKey(Poll) |
7 |
choice = models.CharField(max_length = 200 ) |
8 |
votes = models.IntegerField() |
代码很直白。每个模型都由一个django.db.models.Model的子类实现。每个模型包含一些变量,每个变量对应一个数据库里的字段。 每个字段由类Field的一个实例表示,例如字符类型的字段由CharField实现, 时间 类型的字段则由DateTimeField实现,这样Django就知道每个字段保存的是什么类型的数据了。 每个Field实例的名字(例如 question 和 pub_date )都是机器友好格式的字段名。这些字段会用在你的Python代码里,而数据库则会把它用作字段名。 你可以在Field的第一个参数指定一个可读的名字,这个名字会用在Django内部多个地方。如果没有指定这个名字,Django会使用机器可读的名字。在这个例子里,我们只为 Poll.pub_date 定义了人可读的名字,模型里其他所有的字段,机器可读名字已经可作为人可读名字。 一些Field类有必须含有的元素,例如CharField,必须给它指定 max_length 。这个不仅会用在数据库schema里,也会用在数据验证里,我们很快会看到。 最后,注意到用ForeignKey定义了一个 关系 。它告诉Django每个Choice会关联到一个Poll。Django支持所有的 常用 数据库关系:多对已,多对多和一对一。
激活模型
Django通过模型里的那点代码获取到了很多的信息,通过这些信息,Django可以:
- 为应用创建数据库模式(CREATE TABLE语句) 。
- 创建访问Poll和Choice对象的Python数据库访问API。
但是首先我们先要让我们的项目知道 polls 这个应用已经安装。
原理(Philosophy)
Django应用是“可插拔式”的:你可以把一个应用用在多个项目里,也可以把它发布出去,因为它们不是跟Django的安装绑定的。
再次编辑文件 settings.py ,修改设置INSTALLED_APPS包含字符串 'polls' 。修改后的配置如下:
'django.contrib.contenttypes', |
'django.contrib.sessions', |
现在Django知道要去包含 polls 这个应用了。我们执行 另外 一个命令:
python manage.py sql polls |
你应该会看到类似下面的东西(poll应用的 CREATE TABLE SQL语句):
CREATE TABLE "polls_poll" ( |
"id" integer NOT NULL PRIMARY KEY, |
"question" varchar(200) NOT NULL, |
"pub_date" datetime NOT NULL |
CREATE TABLE "polls_choice" ( |
"id" integer NOT NULL PRIMARY KEY, |
"poll_id" integer NOT NULL REFERENCES "polls_poll" ( "id" ), |
"choice" varchar(200) NOT NULL, |
注意以下几点:
- 实际输出的东西会根据你所使用的数据库而不同。
- 表名由应用的名称(polls)和小写的模型名称 —— poll和choice组合而成并自动生成。(你可以重写这个规则。)
- 主键(IDs)会被自动添加。(同样能可以重写它)
- 为了方便,Django会添加"_id"到外键的字段名上。对的,你同样可以重写它。
- 外键关系由一个REFERENCES语句明确确定。
- 它是为你所使用的数据库量身定制的,所以数据库特有的字段如auto_increment (MySQL),serial (PostgreSQL)或者integer primary key (SQLite)都会自动帮你处理,同样字段名的引号也是如此,例如,是使用双引号还是单引号。这篇教程的作者使用PostgreSQL,所以例子里的输出都是PostgreSQL语法。
- sql命令并不会在你的数据库里执行SQL语句,它只是在屏幕上显示给你看Django认为需要执行哪些SQL语句。如果你想的话,可以复制和粘贴这些SQL语句到你的数据库命令行。但是,我们很快就能看到,Django提供了一个更为简单的方式去执行这些SQL到数据库上。
如果你有兴趣,可以运行以下的命令:
- python manage.py validate -- 检查模型的结构错误。
- python manage.py sqlcustom polls -- 输出所有为应用定义的自定义SQL语句 (例如表修改和约束)。
- python manage.py sqlclear polls -- 根据已存在的表,输出这个应用中必要的DROP TABLE语句。
- python manage.py sqlindexes polls -- 输出这个应用CREATE INDEX语句。
- python manage.py sqlall polls -- sql,sqlcustom和sqlindexes命令产生的SQL语句的结合。
看这些命令的输出可以帮助你更好的 理解 底层发生的事情。 现在,再次运行syncdb在数据库上创建这些模型的表:
syncdb命令会为在INSTALLED_APPS里没有相应数据表的应用运行'sqlall'产生的sql语句。它会为自上次运行syncdb以来新添加的应用建立所有的表,初始化数据和 索引 。你可以在任何时候执行syncdb,它只会创建不存在的表。 阅读django-admin.py documentation以获取 manage.py 这个工具所能做的事情的所有信息。
使用API
现在,我们进入Python的交互 shell 并使用Django提供的API。要进入Python shell,使用这个命令:
我在这里遇到了ImportError: No module named readline这个错误, 解决方法 是下载readline,编译安装,然后重新编译和安装python就可以解决这个问题。 我们使用这个而不是简单的输入"python",是因为 manage.py 会帮你创建项目的环境。“创建项目环境”包括两件事:
- 把polls添加到sys.path里。为了灵活性,Django中的模块通过加点的路径来引用(例如'polls.models')。为了实现这个,polls包必须在sys.path里。
我们已经遇到过一个这样的例子了:the INSTALLED_APPS设置里的列表就是使用点路径表示法。
- 设置DJANGO_SETTINGS_MODULE环境变量,为Django指定了你的settings.py文件的路径。
省略manage.py
如果你不想使用manage.py,没问题,只需要确保mysite和polls 位于Python路径的根目录 (例如import mysite和import polls能正常工作)以及把DJANGO_SETTINGS_MODULE这个环境变量设置到mysite.settings里。
更多的信息可以查看django-admin.py documentation.
在shell里面时,可以 探索 下database API:
>>> from polls.models import Poll, Choice # 导入我们刚写的模型。 |
>>> p = Poll(question = "What's up?" , pub_date = datetime.datetime.now()) |
# 把对象保存进数据库里。你需要明确调用save()。 |
# 现在它有个ID了。注意这里也可能显示1L而不是1, |
# 取决于你使用的是什么数据库。不过这没什么打不了, |
# 它只是表明数据库更倾向于把整型返回成Python的长整型对象。 |
datetime.datetime( 2007 , 7 , 15 , 12 , 00 , 53 ) |
>>> p.pub_date = datetime.datetime( 2007 , 4 , 1 , 0 , 0 ) |
# objects.all()显示数据库所有的poll。 |
等等。 <Poll: Poll object> 完全不能表现出这个对象的 有用信息 。我们可以编辑poll模型(在文件 polls/models.py 里)添加一个__unicode__() 方法 给 Poll 和 Choice来解决这个问题:
class Poll(models.Model): |
class Choice(models.Model): |
为你的模型添加__unicode__()方法是很有必要的。不仅是为了让你自己更好理解交互提示,而且因为对象的表现的使用会贯穿于整个Django自动产生的admin。
为什么是__unicode__()而不是__str__()?
如果你熟悉Python的话,你可能会更喜欢在你的类里添加__str__()而不是__unicode__()方法。我们这里使用__unicode__()是因为Django模型默认使用Unicode,所有保存在数据库的数据在返回的时候都会转化成Unicode。
Django模型有一个默认的__str__()方法叫__unicode__(),它会把结果集转化成UTF-8字节字符串。在各个意味着unicode(p)会返回一个Unicode字符串,而str(p)会返回一个普通的UTF-8编码的字符串。
如果你还是觉得莫名其妙的话,记得把__unicode__()方法加进你的模型中就行了,幸运的话,一切都会如你所想工作。
注意这些都是普通的Python方法,让我们添加一个自定义的方法,用作示范:
class Poll(models.Model): |
def was_published_today( self ): |
return self .pub_date.date() = = datetime.date.today() |
添加 import datetime 会引用Python的 datetime 模块。 保存这些修改然后再次运行 python manage.py shell 新开一个Python交互shell:
>>> from polls.models import Poll, Choice |
# 确保我们新加的__unicode__()正常工作。 |
>>> Poll.objects. filter ( id = 1 ) |
>>> Poll.objects. filter (question__startswith = 'What' ) |
>>> Poll.objects.get(pub_date__year = 2007 ) |
>>> Poll.objects.get( id = 2 ) |
Traceback (most recent call last): |
DoesNotExist: Poll matching query does not exist. |
# 所以Django为这种查找方法提供一个便捷的方式。 |
# 下面相当于Poll.objects.get(id=1)。 |
>>> Poll.objects.get(pk = 1 ) |
>>> p = Poll.objects.get(pk = 1 ) |
>>> p.was_published_today() |
# 调用创建函数创建choice对象,会调用INSERT语句, |
# 把choice添加到已存choice的集合里,并返回这个新创建的Choice对象。 |
# Django会创建一个集合保存外键关联,这个集合可以通过API进行访问。 |
>>> p = Poll.objects.get(pk = 1 ) |
# 显示关联的所有choice —— 目前还没有。 |
>>> p.choice_set.create(choice = 'Not much' , votes = 0 ) |
>>> p.choice_set.create(choice = 'The sky' , votes = 0 ) |
>>> c = p.choice_set.create(choice = 'Just hacking again' , votes = 0 ) |
# Choice对象可通过API访问它关联的Poll对象。 |
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
# 查找pub_date在2007年的poll的所有choice。 |
>>> Choice.objects. filter (poll__pub_date__year = 2007 ) |
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
# 我们使用delete()删除一个choice。 |
>>> c = p.choice_set. filter (choice__startswith = 'Just hacking' ) |
更多关于模型关系的信息,可以看Accessing related objects。想知道更多关于如何使用双下划线通过API实现字段的查找,看Field lookups。要获取数据库API的所有信息,请看Database API reference。 好吧,开篇就到这里,更详细请查看: https://docs.djangoproject.com/en/dev/intro/tutorial01/ Written by icyfire @ 2011.08.05 updated @ 2011.10.09