Walk by faith code, hack, curious

编写第一个Django程序(1)

让我们开始学习怎么使用Django。这个是本次教程的第一部分,接下来会有2,34部分会不断为大家呈现。

首先,说明的是通过这个教程,我们将会带你以前建立一个民意测试投票的小web应用。这个应用主要包括2个部分:

  • 一个公共的前台页面能够让用户看见所有的民意测试以及能够给他们投票。
  • 一个后台的管理页面,让你能够添加修改和删除民意测试。

在这里,我们首先假设你已经安装好了Django,怎么知道Django已经正常运行了呢,就是我们之前说过的在python的交互平台你输入import django,然后不报错,那就说明成功了。或者接着你可以输入django.get_version()来看看到底你安装的是哪个版本.

新建一个工程:

如果你是第一次使用Django,就会注意到Django和现在不管什么语言的开发框架都是差不多的方式,就是刚开始运行一个命令,然后这个命令就会自动建立一个工程的框架出来,还包括一些工程的基本配置文件.Django也无非就是这样的.你可以出入下面这条命令:

django-admin.py startproject mysite

好多时候再*nix系统可能会报错,就是没有权限来运行这个命令,这个时候就去djan-admin.py所在目录给这个文件加权就行了.而我们通过正常的安装方式安装的Django的话,这个django-admin.py已经添加到了系统的路径中了.如果没有在你的系统的路径中,就需要去python的第三方库所在目录site-packages文件下找到python.然后在bin文件下找到它.site-packages/django/bin.

在这里我们说说应该把代码放在什么地方好呢.如果你写过php项目,可能一般就是放在/var/www下面,但是在用Django的时候我们建议不要这么做.因为这样就有可能让别人看见你的代码.

让我们首先来看看工程的目录结构吧:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

来说说这些文件都是什么作用吧.

这个根目录mysite当不用说就是我们工程的根目录了.就是我们在刚才命令中写到的.

manage.py:这个是一个命令行工具,来负责在各个开发过程中的各种处理操作.

在mysite下的mysite目录才真正是整个工程的核心.它就是python的包名,你需要导入很多东西从这个包里.(例如:import mysite.settings)

mysite/__init__.py :这个是一个空文件,它的存在意义就是告诉python这个目录是一个python的包.(如果你是一个python新手请阅读这个文章).

mysite/settings.py:这个就是python 的工程的配置文件,Django设置会告诉你它到底怎么工作的.

mysite/urls.py:这个是Django工程中的url声明文件,相当于Django开发的网站的目录的作用.这里你可以学到更多.

mysite/wsgi.py:这个是Django工程的入口点,请阅读怎么用WSGI部署Django工程来了解详细的内容.

开发服务器:

让我们看看它到底工作了没有.cd到mysite根目录下.然后运行python manage.py runserver .你会看见下面的一些输出:

Validating models...
0 errors found.

Django version 1.4, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

看见这个你就已经启动了Django的开发服务器.它是一个轻量级的完全用python写的一个服务器.我们把它包含到了Django里,为了让开发更加迅速.可以让你在还没有开发完成之前不为部署而烦心.不过要提醒的就是别用这个server部署产品.因为我们是做框架的而不是服务器的.

现在你可以在浏览器里输入http://localhost:8000/来访问这个网站了.你将会看见一个欢迎页.

tip:你可以在启动服务器的时候指定特定的端口,默认的是8000.当然你也可以指定特定的ip地址.这样就能够在局域网的其他机器上访问了.更多的请看runserver参考.

数据库设置:

现在我们能够编辑mysite/settings.py来进行一些配置了,比如数据库的配置,这个文件是一个拥有很多模块级的变量的模块.修改下面的设置来配置你将要使用的开发数据库.

ENGINE:有 'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql' or 'django.db.backends.sqlite3'. Other backends are also available.

NAME:数据库名称,如果你使用的SQLite,那就是该数据库文件的全路径了.包括文件名.如果你指定的这个地址文件不存在,将会在同步数据库的时候创建它.

USER:用户名,SQLite不需要.

PASSWORD:密码

HOST:一般留空就可以的

如果对数据库不熟,那就建议用SQLite了,因为在Python2.5之后就内置了SQLite.所以你不需要再安装其他什么文件.

tip:如果使用的PostgreSQL或者MySQL在这个时候你需要去各种的管理工具里添加一个你命名的数据库,如果在没有的情况下.

在你编辑这个文件的时候可能注意到了INSTALLED_APPS这个配置节点在文件的末尾.这个配置拥有当前Django工程的所有Django实例.而一般这些实例在很多的Django工程中都能够用的.你可以打包部署到别的工程中.

默认的情况下,INSTALLED_APPS包含了这些apps.这些都是内置的:

之所以默认包含这些应用都是因为平常都需要这些的.这些应用至少需要一个数据库表,所以,我们需要在使用之前创建它们:

python manage.py syncdb

这个同步命令会去找settings文件中的INSTALLED_APPS节点中设置的数据库,然后创建需要的表.命令运行时会提示你创建了哪个表,最后还会提示让你创建一个管理员账户.往下走就行.

 

创建对象

到这里你已经完全成功创建了一个工程.接下来要做的就是创建数据模型也就是所谓的对象了.不知道你发现没有,这个都是正常的步骤,首先做的就是确定你要面对的对象,在Django中的每一个应用都是作为包存在的.在创建应用的时候会自动给你组织好目录结构,这样你就不需要手动创建目录,专心于你自己的事情了.

说到这个地方,我们需要给你说明一下project和app到底有什么不一样的地方了.一个app(应用)就是一个web application.用来干一些事情的.例如一个博客系统.用来记录一些事情的.而一个项目(project)它是包含很多的应用和一些列的配置.project就相当于sina网.而其中的一个app就是微博了.一个项目有很多的应用.而一个应用能够属于很多的工程.

你的应用能够在任何的python环境中运行.我们将要创建的民意测试应用就会使一个顶级的模块.这样它就能够直接被导入.而不是作为mysite的一个子模块.

cd到manage.py文件所在的目录,键入下面的命令:

python manage.py startapp polls

这样就会在当前目录生成一个polls文件夹.结构就像是这样的:

polls/
    __init__.py
    models.py
    tests.py
    views.py

这个目录将会含有所有的polls的应用的文件.接下来要做的就是确定我们要面对的对象.

在我们简单的民意调查的应用里,我们需要两个对象,一个是民意调查polls,另外一个就是投票(choices)了.一个调查就是一个问题,也就是说它有一个字段或者说field是问题,还有一个就是发布的时间.而投票对象就是包含一个选项,还有对应的这个选项的被投票数.每一个选项属于一个特定的调查.上面讲到的这些转化为一个python的类就是下面的看到的样子,我们打开polls文件下的models.py文件.编辑它:

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()

代码很简陋,每一个对象都是django.db.models.Model的子类.每一个对象都有一些类变量,他们对应的就是数据库中表的字段.每一个字段都是Field类的实例.例如:CharField就是字符串,DateTimeField就是时间.这个告诉Django每一个字段属于哪种类型.

激活我们的对象

我们刚才写的这些代码已经告诉Django很多的信息了.用这些代码Django能够干下面的事情:

  1. 创建数据库表
  2. 创建一个Python的对象访问api.

但是首先我们还是要告诉Django我们新建了这么一个应用.编辑settings.py文件,修改INSTALLED_APPS设置,添加polls.

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

这个时候Django就知道有这么一个应用了.我们运行下面的命令:

python manage.py sql polls

你会在命令窗口看见下面的代码,是不是很熟悉啊?

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;

其实刚才的操作并没有真正提交到数据库.我们接着做的就是同步到数据库,也就是去数据库建表:

python manage.py syncdb

你可以去这里获取manage.py工具能够干什么的信息.

下面我们来看看Django框架给对应的对象生成了很丰富的交互操作API.

在当前的mysite的目录下键入以下命令:

python manage.py shell

之后我们就键入了python的控制台,让我们来看看下面的这些实用的API吧:

# 导入我们刚才创建的对象

>>> from polls.models import Poll, Choice # 目前还没有数据,所以会返回一个空的列表 >>> Poll.objects.all() [] # 创建一个新的调查项目,因为用到了时间对象所以还要导入datetime >>> import datetime >>> p = Poll(question="What's up?", pub_date=datetime.datetime.now()) # 显示调用save()方法来保存数据 >>> p.save() # 现在我们就能够获取刚才保存的p的id,可能会返回’1L’,这个主要看你用的什么

# 数据库了.没有关系,它只是作为Python中的long integer对象 >>> p.id 1 # 通过python的属性取得数据 >>> p.question "What's up?" >>> p.pub_date datetime.datetime(2007, 7, 15, 12, 00, 53) # 通过修改属性值,然后调用save()方法来修改数据

>>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0) >>> p.save() # objects.all() 获取表中的所有数据

>>> Poll.objects.all() [<Poll: Poll object>]

看见objects.all()返回值了吗?太丑了吧,没有一点意义.让我们通过在对象类中添加一个__unicode__()方法来解决这个问题.

这里有一点要注意的就是为什么是__unicode__()而不是__str__()呢?可能熟悉Python的会在每一个类里添加一个__str__()方法,而不是__unicode__(),而Django在这里使用__unicode__(),因为我们默认的在处理对象的时候采用的Unicode编码,当返回存储在数据库中的数据时Django都会把他们转为Unicode编码.

Django的对象有一个默认的__str__()方法,但是他们还是去调用__unicode__()来把结果转为UTF-8的编码.也就是说直接调用unicode(p)返回的是一个unicode字符串,而str(p)将会返回一个正常的UTF-8编码的字符串.这个的使用取决于你自己了.只是记住给你的对象添加一个__unicode__()方法.

为了便于演示,我们给对象类添加一些自定义的方法:

import datetime
# ...
class Poll(models.Model):
    # ...
    def was_published_today(self):
        return self.pub_date.date() == datetime.date.today()

由于用到了系统时间,我们需要导入Python的时间datetime模块.

保存刚才的修改,然后重新开发shell,python manage.py shell

>>> from polls.models import Poll, Choice # 看看我们添加的__unicode__()方法起作用了没有 >>> Poll.objects.all() [<Poll: What's up?>] # Django提供了很丰富的数据库查找API # 完全由关键字参数来驱动

>>> Poll.objects.filter(id=1) [<Poll: What's up?>] >>> Poll.objects.filter(question__startswith='What') [<Poll: What's up?>] # 获取2007年发布的调查 >>> Poll.objects.get(pub_date__year=2007) <Poll: What's up?> >>> Poll.objects.get(id=2) Traceback (most recent call last): ... DoesNotExist: Poll matching query does not exist.

# 通过主键查找很常见,所有Django就提供了一个快捷的方式

# 下面的操作就是在查找主键为1的调查 >>> Poll.objects.get(pk=1) <Poll: What's up?> # 看看我们自定义的方法起作用没有 >>> p = Poll.objects.get(pk=1) >>> p.was_published_today() False

# 给一个调查添加很多的选项,创建就是调用choice的构造函数来new

# 一个choice对象,然后 >>> p = Poll.objects.get(pk=1) # 显示目前的p所拥有的所有选项. >>> p.choice_set.all() [] # 创建3个choice. >>> p.choice_set.create(choice='Not much', votes=0) <Choice: Not much> >>> p.choice_set.create(choice='The sky', votes=0) <Choice: The sky> >>> c = p.choice_set.create(choice='Just hacking again', votes=0) # Choice有一个API来获取它所属的调查. >>> c.poll <Poll: What's up?> # 调查也有一个api能够获取属于自己的所有调查选项. >>> p.choice_set.all() [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] >>> p.choice_set.count() 3 # API会自动给你组织起对象间的关系. # 可以用双下划线来组织起关系逻辑. # 关系层次不受限制. # 下面就是在查找选项所属的调查的发布日期的年份是在2007的. >>> Choice.objects.filter(poll__pub_date__year=2007) [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] # 让我们用delete()方法来输出一个特定条件的选项: >>> c = p.choice_set.filter(choice__startswith='Just hacking') >>> c.delete()

更多的关于对象关系的请see Accessing related objects

更多关于如何使用双下划线来查找对象的请 see Field lookups.

查看全部的数据库访问api请 see our Database API reference.

-EOF-

相关文章:

编写第一个Django程序(3)

编写第一个Django程序(4)