writing your first Django app, part 2
这一章会建立数据库,创建你的第一个model,和一个关于Django自动生成admin站点的快速入门
建立数据库
打开mysite/settings.py.
默认情况下,配置里使用SQLite。Python包含SQLite,所以你不需要另外下载其它的数据库或者支持数据库的组件。当然,大的项目还是推荐用更大规模的数据库,像PostgreSQl。
如果你想用其它的数据库,下载适当的database blindings并且修改DATABASES‘default’条目来匹配你的数据库链接。
- ENGINE-比如’django.db.backends.mysql’,’django.db.backends.postgresql’,’django.db.backends.mysql’或者’django.db.backends.oracle’。更多的后端在also available。
- NAME-你所用数据库的名字,如果你用的是SQLite,这个数据库将是你计算机的一个文件。在这里,NAME需要是一个绝对路径,包括文件名或者文件。默认的值,**os.path.join(BASE_DIR,’db.sqlite3’)将会存储在你的项目目录下.
如果你不是使用SQLite,需要增加设置比如USER,PASSWORD,HOST,更多细节,请看文档DATABASES
当你编辑mysite/settings.py时,首先修改TIME_ZONE为你自己的时区:
TIME_ZONE = 'Asia/Shanghai'
接下来,注意到文件顶部的INSTALLED_APPS.这里已经包括了Django实例里正在运行的应用。Apps可以用于多个项目,你可以打包并分配它们去其他的项目。
默认情况下,INSTALLED_APPS包括下面的app,都是Django自身附带的:
- django.contrib.admin - admin站点,你马上就会用到它.
- django.contrib.auth - 一个身份验证系统
- django.contrib.contenttypes - 一个内容类别的框架
- django.contrib.sessions - 一个回话框架
- django.contrib.messages - 一个消息框架
- django.contrib.staticfiles - 一个管理静态文件的框架
在我们用数据库之前先要创建它,使用下面的命令:
$ python manage.py migrate
创造models
现在我们定义你的models - 也就是你的数据库设计,和附加的元数据。
哲学
一个model是一个单独的,确定性的关于你的数据的真实资源。它包含不可少的域和你存储数据的行为.Django遵循DRY Principle。目标是把你的数据定义在一个地方,然后以自动的方式获得它。
这也包括数据迁移 - 但不像Ruby,例如,迁移完全从你的models文件获得,所以本质上是一个版本控制让Django可以滚动更新你的数据库样式来匹配你现在的models。
在我们简单的poll app里面,只需要创建两个models:Question和Choice。一个Question包含有一个问题和发布日期,一个Choice包含有两个域:choice的文本和投票的计分。每个Choice都与Question联结。
这个概念可以用简单的Python类来表达,编辑polls/models.py文件:
polls/models.py:
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question,on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
代码很明白,每个model都表现为django.db.models.Model的子类。每一个model都有很多类变量,每一个痘在model中表现为数据库域。
每一个域表现为Field的实例。这里说明了Django有哪些类型的域。
Field实例的名字(比如question_text或则pub_date)是field’s名字,以机器友好的形式。你可以把用于做python代码的值,你的数据库会将它作为列名(column name)。
你可以使用可选的第一个位置参数指定给Field作为适合人类阅读的名字。在这个例子例,只定义了一个适合人类阅读的名字给Question.pub_date。至于models中的其他field,它们的‘试用于机器名字’同样‘适用于人类’。
一些Field需要添加必须的参数,比如Charfield,要求你给它一个max_length。
Field也可以有很多可选的参数,在这里例子里,我们可以看到vote有默认参数default,它的值为0.
最后,记住关系定义,使用ForeignKey,这里告诉Django每一个Choice都和单一的Question相关联。Django支持普遍的数据库关系:多对一,多对多,和一对一。
触发models
一点model代码告诉Django大量的信息。现在Django可以:
- 为这个app创建一个数据库schema
- 创建一个Python数据库入口,用以访问Question和Choice对象
但是首先,我们需要告诉项目,polls app已经安装。
哲学
Django的apps是‘可拔式’的:你可以把一个app用于很多projects,你可以发布你的app,因为它们并不绑定给定的Django安装环境。
为了让project包含app,我们需要引用它的配置类,添加到INSTALLED_APPS设置。PollsConfig类在polls/apps.py,它的点式路径(dotted path)是’polls.apps.PollsConfig‘,编辑mysite/settings.py文件然后添加点路径到INSTALLED_APPS。像下面这样:
mysite/settings.py:
INSTALLED_APP = [
'polls.app.PollsConfig,
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
现在,Django知道包含了polls app,让我们运行另一条命令:
$ python manage.py makemigrations polls
你应该看到类似下面的输出:
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Choice
- Create model Question
- Add field question to choice
当运行makemigrations时,你告诉Django你对你的models做了一些更改而且你希望你的变化作为migration保存下来。
Migrations是怎样在Django存储你的models(也就是你的数据库schema)-它们存储在硬盘上。如果你愿意你可以阅读这个migration;它存储在polls/migrations/0001_initial.py.不用担心,你不需要每次都去读它们,只是它们设计出来是可人为编辑的,在万一你需要手工扭转Django改变的东西。
这些这个命令可以为你运行migrations,可以自动管理你的数据库schema-这个命令叫做migrate,一会就要提到-但是首先,让我们看看migration会运行怎样的SQL。sqlmigrate命令拿到migrations的名字之后返回它的SQL。
$ python manage.py sqlmigrate polls 0001
如果你感兴趣,你可以运行python manage.py check;这个可以检查你项目的任何问题,在不制造migrations或者触碰数据库的情况下。
现在,再一次运行migrate,用以在你的数据库创造models表。
$ python manage.py migrate
migrate命令接收所有没有应用过的migrations(Django追踪你用过的每一个migration,方法是在你的数据库使用一个特别的表,叫做django_migrations)且对你的数据库应用它们 - 本质上,在你对models作出改变后同步执行这些命令。
Migration是一个强力的功能,让你任何时候都能改变自己的models,在你开发你的项目时,除了不能删除你的数据库或表,也不能创建新的 - 它特定地用来动态更新你的数据库,而不会遗失数据。在后面的章节会对这个功能涉及很深,但是现在,记住这个“三步法”应用你的model改变。
- 改变你的models(在models.py)
- 运行 python manage.py makemigrations 来为这些变化创建migrations
- 运行 python manage.py migrate 来对数据库应用这些变化
阅读 django-admin documentation,里面有完整的信息,可以在里面获取 manage.py 工具的用法。
应用API
现在,让我们跳入交互式Python shell和搞搞Django的自由API。调用Python shell,使用以下命令:
$ python manage.py shell
不能简单的输入“python”,因为manage.py设置了DJANGO_SETTINGS_MODULE环境变量,它让Django可以import你的mysite/settings.py文件路径.
绕开 manage.py
如果你不想用manage.py,没问题。只要把DJANGO_SETTINGS_MODULE设置的环境变量复制到mysite.settings,启动一个普通的python shell,然后建立Django:
>>>import django >>>django.setup()
你必须和manage.py的同一个目录下运行python shell,或者确认这个目录在python的路径上,或者 import mysite有效
一旦你进入了shell,试试database API:
>>> from polls.models import Question, Choice
>>> from django.utils import timezone
>>> q = Question(question_text="What's up?", pub_date=timezone.now())
>>> q.save()
等一会,是一个十足的无帮助的表现形式,让我们为Question和Choice添加一个__str__:
polls/models.py:
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
加入__str__()很重要,不仅仅是方便你在命令行提示你,表现形式同样遍及Django的整个自动化里面。
让我们加入一个自定义方法,像下面一样
polls/models.py:
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
#...
def was_publised_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
这个函数的意义显而易见,如果你想知道更多的timezone方法,可以阅读官方文档time zone support docs.
再次输入python manage.py shell,进行如下操作:
>>> from polls.models import Question, Choice
# 普通的查询
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
# 查询本年度发布的question
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
# 查询不存在的id,这会触发exception
>>> Question.objects.get(id=2)
Traceback (more rencent call last):
...
DoesNotExist: Question matching query does not exist.
# 常见的查询方法是查阅主键(primary key),所以Django提供了一个捷径
# 方法就是primary-key = pk
# 这个方法和Quesion.objects.get(id=1)是一样的
>>> Question.objects.get(pk=1)
<Question: What's up?>
# 确认一遍我们定义的方法生效了
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# 为q设置Choice对象
>>> q.choice_set_all()
<QuerySet [] )
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much)
>>> q.choice_set.create(choice_text='The sky', votes=0)
<CHoice: The sky)
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
<Question: What's up?>
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice.set.count()
3
# 查询在本年度发布的Choice
# 使用双下划线来分离方法
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# 让我们删除一个choices,使用delete()
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delet()
更多的model关系信息,请看Accessing related objects。想知道更多通过使用双下划线来用API的方法,请看Field lookups。完整的数据库API细节,请看Database API reference
Django admin的介绍
哲学
生成管理员站点让你的职员或客户可以增删改,但建立这个站点很无聊。所以,Django完全自动化的为models创建了admin界面。
可以用这个admin界面来发布新闻,事件,和比赛积分。
这个界面不是为网站的游览者设立的,而是为网站的管理者设立的。
建立一个admin用户
运行以下的命令来创建一个可以登录admin网页的账号:
$ python manage.py createsuperuser
接下来跟着提示输入相关信息即可,注册成功并确保服务器在运行时即可登录http://127.0.0.1:8000/admin/。之后你就能看到admin登录界面了。(界面的语言默认在settings.py)里面设定,简体中文建议LANGUAGE_CODE = ‘zh-hans’)。
登录进入后你可以看到几个可以编辑的条目,分别是groups 和 users。它们由django.contrib.auth提供,是Django自带的身份验证框架。
让poll app 可以在admin里面修改
一开始你在admin界面是看不到自己的app的,只要做一件事就可以了:
polls/admin.py:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
探索admin的功能
现在进入admin界面就会看到下面这样:
点击’Question’,你可以看到可以修改的列表,我们也可以看到之前创建的”What’s up?”:
点击”What’s up”,就可以编辑它了。