【译】自己动手写Django app,第一部分【完】

原文地址:https://docs.djangoproject.com/en/1.4/intro/tutorial01/

让我们通过例子来学习。

通过这个教程,我们将带领你了解创建基本的调查程序。

它将包括两部分:

一个让人们可以查看调查和投票的网址;

一个可以让你增加,改变和删除调查的管理员网址。

假设你已经安装了Django。你可以在python交互式解释器中输入 import django,如果成功,没有错误的话,就说明Django已经安装。

一、创建一个项目

如果这是你第一次用Django,你必须注意一些初始的设置。也就是说,你需要自动生成一些代码来建立一个Django项目--Django实例设置的集合,包括数据库的配置,Django相关的选项和应用程序相关的设置。

从命令行上cd到你想储存你代码的目录,然后输入django-admin.py startproject mysite,这将创建在当前目录创建一个mysite目录。

(不同发行版本可能有不同的脚本名称:如果你用linux发行版的包管理器(apt-get或者yun)安装Django,django-admin.py可能被重命名为django-admin,你可以在接下来的命令行都忽视.py继续这个文档。)

(Mac OS许可:如果你使用Mac OS X,当你尝试运行django-admin.py startproject时你可能看到”permission denied“的消息。这是因为在基于Unix的系统像OS X,只有一个文件被标记为”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/django/bin下找到它(site-packages是你python安装目录下的一个目录),然后把django-admin.py链接到你的路径下,不如说/usr/local/bin。

(这些代码该存在什么地方:如果你用的是php,你可能习惯于把你的代码放在服务器的根文档下(在一个地方比如说/var/www)。但是用Django,你不需要这样,因为这别人就有可能通过网络看到你代码风险,这是不安全的。

把你的代码放在你跟物件目录之外,比如说/home/mycode.)

让我们来看一下startproject创建了什么:

mysite:

    manage.py

    mysite/

        __init__.py

        settings.py

        urls.py

        wsgi.py

(和你看到的不匹配?项目默认的布局最近改变了,如果你看到的是一个“平坦的”布局(也就是说没有mysite/目录),你可能用一个不符合这个教程版本的Django,你可以切换到老版本的教程或者使用新版本的Django。)

这些文件是:

外面的mysite/目录只是一个你项目的容器,它的名字和Django无关,你可以把它重命名成任何你喜欢的名字;

manage.py:一个让你和Django项目多途径交互的命令行实用程序,你可以在django-admin.py 和manage.py中了解更过关于manage.py的细节;

内部的mysite/目录是你项目的实际python包,它的名字是python包的名字,你可以通过导入(import mysite.settings)来使用它里面的一切;

mysite/__init__.py:一个空文件,用来告诉python这个目录应该被当成一个python包处理。(如果你是个新手,你可以在官方文档中了解到更更多关于包的信息。)

mysite/settings.py:Django项目的设置和配置。Django设置会告诉你设置时如何工作的;

mysite/urls.py:Django项目的URL声明,你Django支持的网址的目录,你可在URL分配中了解到个呢更多关于URLs的信息;

mysite/wsgi.py:兼容WSGI的网络服务器运行你项目的进入点,你何以在如何部署WSGI中了解到更多细节;

二、开发服务器

让我们来验证它已经工作了。改变目录到外面的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中包含了这个,因此你可以快速的开发而不用担心如何处理配置一个上线服务器--比如说Apache--直到你准备上线了。

现在要标注一下:不要在任何类似的上线(生产)环境中使用这个服务器。这只是在开发是使用的。(我们现在是在创建网络架构,不是网络服务器。)
现在既然服务器已经运行起来了,你可以通过服务器访问http://127.0.0.1:8000/,你将会看到一个愉快的,淡蓝色蜡笔写的“Welcome to Django”的网页,你成功了!

(改变端口:默认情况下,runserver命令在内部IP端口8000启动开发服务器,如果你想改变服务器的端口,在命令行的参数中声明。比如说,下面的命令在8080端口启动服务器: python manage.py runserver 8080;如果你想改变服务器的IP,把它和端口一起在命令行中声明,因此为了监听所有公共IP(当你想在其他电脑上展示你的工作的时候很有用),用:python manage.py runserver 0.0.0.0:8000,你可以在runserver参考手册中找到更多关于开发服务器的文档。)

三、建立数据库

现在,编辑mysite/settings.py,这是一个代表Django设置的带有模块层变量的常规python模块,改变DATABASE‘default’关键词使之和你的数据库连接设置相匹配。

ENGINE:要么是‘django.db.backends.postgresql_psycopg2',要么是’django.db.backends.mysql',要么是'django.db.backends.sqlites3',或者是'django.db.backends.oracle',其他的选项详见文档;

NAME:数据库的名字。如果你用的是SQLite,数据库可能是你电脑上的一个文件,这种情况下,NAME应该是绝对值路径,包括数据库文件名,如果文件不存在,当你第一次同步数据库的时候系统将会自动创建该文件。在明确路径是,总是使用正斜杠,甚至是在windows上(比如说,C:/homes/user/mysite/sqlite3.db);

USER:数据库的用户名(SQLite设置为空);

PASSWORD:数据库密码(SQLite设置为空);

HOST:存放数据库的主机,如果数据库服务器是在同一个物理机器上面,这是该选项为空字符串;

如果你是数据库方面的新手,我们建议使用SQLite,这是设置ENGINE为‘django.db.backends.sqlite3’并且把NAME设置成存放你数据库的地方就行了。在python2.5和以后的版本中,SQLite已经包含在python中,因此你不需要安装任何东西来支持你的数据库。

(注意:如果你使用的是postgreSQL或者是mysql,确定你已经创建了相关数据库,你可以在数据库交互提示上通过”CREATE DATABASE database_name;”完成;如果你使用的SQLite、你不必提前创建任何东西,在必要的时候数据库文件会被自动创建。)

当你在编辑settings.py时,把TIME_ZONE设置成你的时区,默认值是美国中部时区(芝加哥)。

同时,注意文件地步的INSTALL_APPS设置,它列举所有Django应用程序的名字,它们是已经激活的Django实例。这些应用程序可以在许多项目中使用,你也可以打包并发布它们使它能够在别人的项目中也能使用。

默认情况下,INSTALL_APPS包含下面的应用程序,这些都是Django绑定的:

django.contrib.auth:一个认证系统;

django.contrib.contenttypes:内容类型框架;

django.contrib.sessions:会话框架;

django.contrib.sites:单个Django安装管理多个站点的框架;

django.contrib.messages:一个消息留言框架;

django.contrib.staticfiles:一个管理静态文件的框架;

为了方便一般情况,这些应用程序默认情况下被自动包含了。

每个应用程序至少用到了一个数据库的表,因此,我们需要创建数据库的表,这样我们才能使用它们。为了这样做,运行下面的命令:python manage.py syncdb。

syncdb命令查看INSTALLED_APPS设置然后根据settings.py文件里数据库设置创建必要的数据库表,你将会看到每个表被创建的信息,接下来你将会获得一个提示问你是否需要创建认证系统的超级账户,去做吧。

如果你感兴趣,你可以运行数据库的命令行,并且输入\dt(PostgreSQL),SHOW TABLES;(MySQL),或者.schema(SQLite)来显示Django创建的表。

(对于极简影像派艺术家:就像我们上面说到的一样,默认程序已经包含了一半情况,但不是每个人都需要的。如果你不需要它们所有或者部分,你可以在运行syncdb前在INSATALLED_APPS自由的注释掉或者删掉相关行,syncdb命令将只会创建INSTALLED_APPS中应用程序的表。)

四、创建模型(models)

现在,你的环境——一个项目——已经建立i来了,你应该开始做一些事情了。

你用Django写的每个程序都是由python包组成的,某些在python路径下,他们遵行相关公约。Django自带了一个自动生成一个应用程序基本目录结构的功能,因此你可以不用关注创建目录而只专心写代码。

(项目VS应用程序:一个项目和一个应用程序有什么区别呢?一个应用程序是一个做一些事情的网络应用程序——比如说,一个网络博客系统,一个公共唱片记录的数据库或者是一个简单的调查程序。一个项目是对特定的网站的一些列配置和应用程序的集合。一个项目可以包含多个应用程序,一个应用程序可以在多个项目中。)

你的应用程序可以存在在你python路径下任何地方。在这个教程中,我们将会在manage.py文件的边上创建我们的调查应用程序这样他就可以作为项目自己顶层模块被引用(而不是一个mysite的子模块)。

为了创建你的应用程序,确定你在和manage.py同一个目录下,然后输入命令:python manage.py startapp polls,这将创建一个polls目录,它的布局是这样的:

polls/

    __init__.py

    models.py

    tests.py

    views.py

这个命令结构将容纳投票应用程序。

写网络应用程序的第一步是定义模型(models)——从本质上来说,就是你的带有额外元数据的数据库布局。

(哲学:一个模型是你数据的一个单个的,确定的本源。它包含了你存储数据的必要的空间和行为。Django遵行DRY原则,这个目标是在一个地方定义你的数据模型然后自动导出来自它的东西。)

在我们简单的调查程序中,我么你创建了两个模型:polls和choices,一个调查有一个问题和一个公开日期,一个选择有两个空间:选择的内容和投票标签。每个选择都和一个调查相关联。

这些概念可以通过简单的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每个数据空间是什么类型。

每个Field实例的名字(比如说question或者pub_date)都是空间的名字,他们是以机器友好的格式存在的。你可以在你的pyhton代码中用这个值,你的数据库将会把它作为列的名字。

你可以用一个额外的第一个位置的参数把Field设计成一个人类可读的名称。这一般用在Django内省部分的一队,并兼作文档。如果没有提供这个空间,Django将会用机器可读的名字。这个例子中,我们为Poll.pub_date只定义了一个人类可读的名字。对这个模型中所有其他的空间,这个空间的机器可读的名字也能作为人类可读的名字。

一些Field类有需要的元素。比如说,CharField要求你给他一个max_length。这不仅在数据库架构中用到,也在验证中用到,我们很快就会看到。、

最后,用ForeignKey定义关系,它告诉Django每个Choice关联到单个Poll。Django支持所有一般的数据库关系:多对一,多对多和一对一。

四、激活模型

那一小段模型代码给Django许多信息,有这些信息,Django就能:

    为这个应用程序创建一个数据库构架(CREATE TABLE 表述);

    为访问Poll和Choice对象创建基于python的数据库访问API;

但是首先我们应该告诉我们的项目polls应用程序已经安装了。

(哲学:Django应用程序是”可插入的“,你可以在多个项目中用一个应用程序,你也可以发布应用程序,因为他们没必要绑定在一个给定的Django安装上。)

再次编辑settings.py文件,修改INSTALLED_APPS设置包含字符串”polls“,这样它就看起来像这样:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'polls',
)
现在Django知道包含polls应用程序。让我们运行其他的命令:python manage.py sql polls,你应该看到类似于下面的信息(CREATE TABLE 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") DEFERRABLE INITIALLY DEFERRED,
    "choice" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
COMMIT;
注意下面事项:

    根据你使用的数据库,输出可能不一样;

    表的名字是由应用程序的名字(polls)和模型——poll和choice——的小写名字自动生成的(你可以override这种做法);

    主键(IDs)自动增加(你可以override这种做法);

    默认习惯,Django追加”_id“到主键空间名字(你也可以override这种做法);

    外键是通过REFERENCES描述来明确关系的;

    对你现在使用的数据库来说,这是可定做的,因此明确的数据库空间类型比如说auto_increment(MySQL), serial(PostgreSQL)或者integer primary key(SQLite)会自动为你处理掉。空间名字的引号也是一样的——比如说,用双引号或者单引号。这篇教程的作者是用PostgreSQL,因此离子的输出时PostgreSQL语法;

    sql命令事实上不在你的数据库中运行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命令的集合;

查看这些输出文件可以帮你理解实际上发生了什么。

现在再运行syncdb来创建数据库的模型表:python manage.py syncdb。


syncdb命令对所有在INSTALLED_APPS里而不在数据库的应用程序从你电脑运行SQL语句。当你最后一次运行syncdb时,它创建了所有的表,并且对所有程序的初始化的数据和索引已经增加到你的项目。syncdb语句可以在任何时候被调用,而且它只创建不存在的表。

更多关于manage.py能做什么的信息可以阅读django-admin.py文档。

五、和API玩

现在,让我们跳进python交互脚本和Django提供的API玩。为了召唤python脚本,使用下面命令:python manage.py shell。我们用这个命令而不是直接输入”python“,因为namage.py会设置DJANGO_SETTINGS_MODULE环境变量,它会把Django的python导入路径给settings.py文件。

(绕过manage.py:如果你不喜欢使用manage.py,没问题。只需设置DJANGO_SETTINGS_MODULE环境变量为mysite.settings然后从和manage.py在相同目录的地方运行python(或者确保目录是在python路径上,这样import mysite有效。)更多信息请参考django-admin.py文档。)

当你在shell脚本时,探索数据库的API:

>>> from polls.models import Poll, Choice   # Import the model classes we just wrote.

# No polls are in the system yet.
>>> Poll.objects.all()
[]

# Create a new Poll.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> p = Poll(question="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> p.save()

# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> p.id
1

# Access database columns via Python attributes.
>>> p.question
"What's new?"
>>> p.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> p.question = "What's up?"
>>> p.save()

# objects.all() displays all the polls in the database.
>>> Poll.objects.all()
[<Poll: Poll object>]
等一会儿,<Poll:Poll object>显然是对这个对象不友好的表示,让我们通过编辑model(在polls/models.py文件)给Poll和Choice增加一个__unicode__()方法来修复它:
class Poll(models.Model):
    # ...
    def __unicode__(self):
        return self.question

class Choice(models.Model):
    # ...
    def __unicode__(self):
        return self.choice

向模型增加__unicode__()方法很重要,不仅仅是为了你处理交互提示时的正常神智,也因为对象代表在整个Django自动生成admin是也会用到。

(为什么是__unicode__()而不是__str__()?:如果你对python熟悉的话,你可能有向你的类增加__str__()方法的习惯,而不是__unicode__()。我们这里使用__unicode__()因为Django模型默认处理Uniocde,数据库中所有储存的数据在返回时都被转换成Unicode。Django模型有一个默认的__str__()方法,它调用__unicode__()方法把结果转化成UTF-8的字符串。这意味着unicode(q)将返回一个Unicode字符串,str(q)返回一个正常的用utf-8编码的字符串。如果这些都让你费解的话,你只要记住向你的模型增加__unicode__()方法。运气好的话,事情应该只为你工作。)

注意这些常规python方法,让我们增加一个定制的方法,只是为了演示:

import datetime
from django.utils import timezone
# ...
class Poll(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
注意增加import datetime和from django.utils import timezone,他们分别的参照python标准datetime库和django.utils.timezone的Django的时区相关的实用程序。如果你对python中处理时区不熟悉,你可以在时区支持文档中了解更多。

保存这些改变然后运行python manage.py shell再开始一个新的python交互式shell脚本:

>>> from polls.models import Poll, Choice

# Make sure our __unicode__() addition worked.
>>> Poll.objects.all()
[<Poll: What's up?>]

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Poll.objects.filter(id=1)
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]

# Get the poll that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Poll.objects.get(pub_date__year=current_year)
<Poll: What's up?>

>>> Poll.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Poll matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
<Poll: What's up?>

# Make sure our custom method worked.
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_recently()
True

# Give the Poll a couple of Choices. The create call constructs a new
# choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a poll's choices) which can be accessed via the API.
>>> p = Poll.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> p.choice_set.all()
[]

# Create three choices.
>>> 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 objects have API access to their related Poll objects.
>>> c.poll
<Poll: What's up?>

# And vice versa: Poll objects get access to Choice objects.
>>> p.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any poll whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(poll__pub_date__year=current_year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# Let's delete one of the choices. Use delete() for that.
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()
模型相关的更多细节请参考Accessing related objects。更多关于如何使用双下划线通过API强调空间查找,请参考Field lookups。关于数据库API更完整的细节,请参考Database API reference。

当你觉得对这些API适应之后,读第二部分教程了解Django的自动管理。

《第一部分,完!》

你可能感兴趣的:(【译】自己动手写Django app,第一部分【完】)