没啥好说的,就这么着吧~上周小车失窃,着实让我郁闷了两天;可哥结婚今天请吃饭,没去,短信说明年回去看他,没回,估计是被维曦他们一帮人灌倒了
原文见 5. Models and Databases
5. 模型与数据库
与数据库打交道通常是一件棘手的事情。在Django中,通过object relational mapping(ORM)这一功能很好地克服了上述问题,同时Django通过模型封装了数据表。从本质上说,模型就是python的对象,它描述了你的数据模型/表。所有你需要做的就是操作相应的Django对象,而非通过SQL直接访问数据库。在本章中,我们会介绍如何安装数据库以及Rango需要的模型。
5.1. Rango’s Requirements
首先,我们先过下Rango的数据需求。下面的列表给出了Rango数据需求的关键细节。
- Rango本质上是一个网页目录——一个包含到其他站点链接的网站
- 有很多不同的网页分类,每个分类包含一定数目的链接。我们在第一章中假设有一个一对多的关系。见如下关系表。
- 分类有名字,访问数以及喜欢数。
- 页面属于某个分类,有标题,URL以及访问数。
5.2. 告诉Django你的数据库
在我们创建任何模型之前,首先要建立数据库的配置。要完成这个,打开文件settings.py
,定位到字典DATABASES
。现在,修改default
键值对如下。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': DATABASE_PATH,
}
}
也要创建变量DATABASE_PATH
,并把它添加到settings.py
的顶部,与之前定义的路径放到一起。
DATABASE_PATH = os.path.join(PROJECT_PATH, 'rango.db')
这里,我们定义默认的数据库使用SQLite Django backend。这使得我们能够访问轻量级的python数据库。SQLite,非常适合用于开发。其他需要设置的值是NAME
键值对,我们将其设置成DATABASE_PATH
。对于SQLite数据库,余下的USER
,PASSWORD
,HOST
和PORT
是不需要的,因此可以放心的移除。
5.3. 创建模型
在settings.py
中配置好数据库之后,现在我们可以来创建用于Rango应用的原始数据模型了。
在rango/models.py
中,定义两个类——两者都需要继承django.db.models.Model
。这两个python类定义了表示分类
和页面
的两个模型。定义Category
和Page
模型如下。
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
在定义模型的时候,需要指定属性列表以及可选参数相关的类型。Django提供了大量内置的类型。常用的类型如下。
CharField
,存储字符数据的字段(例如,字符串)。指定max_length
来表示可存储的最大字符数。
URLField
,跟CharField
很像,不过用于存储资源URL。你也可以指定一个max_length
参数。
IntegerField
,存储整数。
DateField
,存储python的datetime.date
。
完整的列表见Django documentation on model fields。
对于每一个字段可以指定unique
属性。如果设置为True
,在整个数据库模型中,给字段只允许存在唯一的实例。例如,对于我们上面定义的Category
模型。字段name
设置为unique——因为每个分类的名字必须是唯一的。
这用于在你想将某个字段作为额外的数据库键时。你还可以对每个字段指定其他的属性,例如指定一个默认值(default='value'
),以及某个字段是否可以为NULL
(null=True
)。
Django还提供了一个简单的机制允许我们关联模型/数据库表。这个机制通过三种字段类型来实现,具体如下。
ForeignKey
,该字段用来表示一对多的关系。
OneToOneField
,该字段定义严格的一对一关系。
ManyToManyField
,该字段表示多对多关系。在上面的示例模型中,Page
模型中字段category
就是ForeignKey
类型。这使得我们能够建立与模型/表Category
一对多的关系,将其作为字段构造函数的一个参数。你应该注意到Django在每个模型对应的表中自动创建了一个ID字段,所以你没有必要显式的为每个模型定义一个主键,Django使得你的生活轻松多了!
5.4. 创建并同步数据库
定义好了模型,就可以让Django施法了,在数据库中创建表。我们需要使用脚本manage.py
,想下面这样调用:
$python manage.py syncdb
接下来你可以跟着屏幕上的提示做。你可以看到Django在你的数据库中创建了很多表。引入注意的是这两张表rango_category
和rango_page
。它们分别对应两个Django模型Category
和Page
。示例脚本产生的输出如下。
$ python manage.py syncdb
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table rango_category <-- Rango Category model
Creating table rango_page <-- Rango Page model
You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use '<YOUR USERNAME>'): <ENTER A USERNAME>
Email address: <ENTER YOUR E-MAIL ADDRESS>
Password: <ENTER PASSWORD>
Password (again): <ENTER PASSWORD AGAIN>
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
你可能会询问是否创建一个超级账户,就像上面的例子中那样。在本指南的后续部分会使用超级账户来访问Django管理接口,所以还是建议你克服困难创建一个帐号(so we recommend that you bite the bullet and set up an account now)。输入yes
,然后输入用户名,邮箱和密码。做完这些,脚本成功退出。切记要记下超级账户的用户名和密码。
当这个过程结束后,你将会在工程目录中看到一个名为rango.db
的文件。
5.5. Generated SQL
数据库同步过程本质上就是把Django模型转成SQL表。可以运行python manage.py sql rango
来查看生成的SQL。它会输出与使用的数据库相关的SQL语句。注意,虽然我们没有在模型中指定id
属性,Django会自动给每个模型分配一个id
。你还会注意到表rango_page
中Category
被指定为外键。
BEGIN;
CREATE TABLE "rango_category" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(128) NOT NULL UNIQUE
)
;
CREATE TABLE "rango_page" (
"id" integer NOT NULL PRIMARY KEY,
"category_id" integer NOT NULL REFERENCES "rango_category" ("id"),
"title" varchar(128) NOT NULL,
"url" varchar(200) NOT NULL,
"views" integer NOT NULL
)
;
COMMIT;
既然Django在数据库之上提供了一层封装,我们需要关注的就是模型。不过,如果你愿意你还是可以直接在数据库中执行SQL命令。细节见Official Django Documentation on running custom SQL。
5.6. Django模型与Django Shell
在我们把注意力转移到Django admin接口之前,值得注意的是你可以通过Django shell访问Django模型——非常有助于调试。我们会通过创建一个Category
实例来说明这个方法。
在Django工程的根目录再次调用manage.py
来进入shell。运行下面的命令。
$python manage.py shell
这会启动一个Python解释器的实例,并加载工程的设置。之后你就能够与模型互动了。下面的例子中终端的输入说明了这个功能。行间的注释说明了每个命令是做什么的。
# Import the Category model from the Rango application
>>> from rango.models import Category
# Show all the current categories
>>> print Category.objects.all()
[] # Returns an empty list (no categories have been defined!)
# Create a new category object, and save it to the database.
>>> c = Category(name="Test")
>>> c.save()
# Now list all the category objects stored once more.
>>> print Category.objects.all()
[<Category: test>] # We now have a category called 'test' saved in the database!
# Quit the Django shell.
>>> quit()
在这个例子中,我们首先导入了需要处理的模型。然后输出所有存在的分类,当然了没有分类输出因为我们的表是空的。之后,我们创建并保存了一个分类,然后再次输出所有分类。第二个print
应该会输出刚刚添加的Category
。
5.7. 配置管理接口
Django的一个牛比特性就是提供了一个内置的,基于网页的管理接口,通过这个接口我们可以浏览修改模型相应的表中的数据。跟其他做法一样,在我们能够使用管理接口之前我们需要配置它。
首先,打开工程文件setings.py
。这个文件位于工程配置目录。在这个文件中,找到INSTALLED_APPS
元组,取消掉django.contrib.admin
之前的注释。现在元组看起来应该是下面这个样子。看下行间的注释不难找到取消注释的行。
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', # THIS LINE SHOULD NOW BE UNCOMMENTED
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'rango',
)
做好了这些,保存文件并同步数据库。需要做这些是因为django.contrib.admin
应用需要表来完成功能。要同步数据库,再次运行命令syncdb
。
$ python manage.py syncdb
你应该会看到表django_admin_log
已经创建好了。一旦完成,打开工程的urls.py
文件。这个文件位于工程配置目录。在这个文件里面,首先取消导入语句后面的两行。还要保证URL模式/admin/
存在,并指向admin.site.urls
模块,像下面这样。
from django.conf.urls import patterns, include, url
from django.conf import settings
# Uncomment the next two lines to enable the admin:
from django.contrib import admin # UNCOMMENT THIS LINE
admin.autodiscover() # UNCOMMENT THIS LINE, TOO!
urlpatterns = patterns('',
url(r'^rango/', include('rango.urls')),
url(r'^admin/', include(admin.site.urls)), # ADD THIS LINE
)
if settings.DEBUG:
urlpatterns += patterns(
'django.views.static',
(r'media/(?P<path>.*)',
'serve',
{'document_root': settings.MEDIA_ROOT}), )
快完成了!接下来,我们需要告诉Django的admin
应用有哪些模型需要通过admin接口来访问。要完成这些,我们需要在rango
应用目录下创建一个名为admin.py
的文件。添加下面的代码到这个文件中。
from django.contrib import admin
from rango.models import Category, Page
admin.site.register(Category)
admin.site.register(Page)
它将模型注册到了管理接口中。如果我们还有其他的模型,我们只要简单的将模型作为参数来调用admin.site.register()
。
做好了所有这些修改,启动或者重启Django开发服务器,访问http://127.0.0.1:8000/admin/
。你应该会看到一个登录框,需要输入用户名和密码。输入设置数据库时创建的超级帐号的用户名和密码,你会看到一个如图2所示的网页。
点击Rango
部分的Category
链接。从这里,你应该能看到之前通过Django shell创建的test
分类。试着删除分类,因为我们接下来会通过一个填充脚本来填充数据库。这个接口易于使用。花几分钟来创建,修改以及删除分类和页面。你还可以在Auth
应用的User
中添加用户,让他能够登录到工程的管理接口。
5.8. 创建填充脚本
在课程的开发过程中,非常可能在某个时间点需要修改Django模型。当你需要这么做时,最简单的选择——不使用外部工具|局势重建整个数据库并运行python manage.py syncdb
…!由于这项工作非常单调,一个不错的做法就是为数据库创建一个脚本,我们称之为填充脚本(population script)。这个脚本用来自动填充测试数据,这无形中节省你大量的时间。
要创建Rango数据库的填充脚本,我们在Django工程根目录(例如<workspace>/tango_with_django_project/
)中创建了一个python模块。新建文件populate_rango.py
,添加下面的代码。
import os
def populate():
python_cat = add_cat('Python')
add_page(cat=python_cat,
title="Official Python Tutorial",
url="http://docs.python.org/2/tutorial/")
add_page(cat=python_cat,
title="How to Think like a Computer Scientist",
url="http://www.greenteapress.com/thinkpython/")
add_page(cat=python_cat,
title="Learn Python in 10 Minutes",
url="http://www.korokithakis.net/tutorials/python/")
django_cat = add_cat("Django")
add_page(cat=django_cat,
title="Official Django Tutorial",
url="https://docs.djangoproject.com/en/1.5/intro/tutorial01/")
add_page(cat=django_cat,
title="Django Rocks",
url="http://www.djangorocks.com/")
add_page(cat=django_cat,
title="How to Tango with Django",
url="http://www.tangowithdjango.com/")
frame_cat = add_cat("Other Frameworks")
add_page(cat=frame_cat,
title="Bottle",
url="http://bottlepy.org/docs/dev/")
add_page(cat=frame_cat,
title="Flask",
url="http://flask.pocoo.org")
# Print out what we have added to the user.
for c in Category.objects.all():
for p in Page.objects.filter(category=c):
print "- {0} - {1}".format(str(c), str(p))
def add_page(cat, title, url, views=0):
p = Page.objects.get_or_create(category=cat, title=title, url=url, views=views)[0]
return p
def add_cat(name):
c = Category.objects.get_or_create(name=name)[0]
return c
# Start execution here!
if __name__ == '__main__':
print "Starting Rango population script..."
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tango_with_django_project.settings')
from rango.models import Category, Page
populate()
虽然代码看起来有很多,不过做的事情却相对简单。因为我们在文件开头定义了一系列函数,代码从结尾开始执行|找到这一行if __name__ == '__main__'
。然后导入Rango的设置和模型Category
以及Page
,最后调用函数populate()
。
函数populate()
会调用函数add_cat()
和add_page()
,这两个函数分别负责创建新分类和新页面。当我们创建单独的Page
模型实例并保存到数据库时,populate()
会保存分类的标签。最后,遍历模型Category
和Page
,输出所有的Page
实例和相应的分类。
注意——我们使用的简便的函数get_or_create()
来创建模型实例。关于这个函数的细节查阅官方文档。那里会解释为什么在返回值中传递索引[0]
。
保存,把目录改到工程根目录运行脚本,通过命令$ python populate_rango.py
执行模块。你应该会看到类似下面的输出。
$ python populate_rango.py
Starting Rango population script...
- Python - Official Python Tutorial
- Python - How to Think like a Computer Scientist
- Python - Learn Python in 10 Minutes
- Django - Official Django Tutorial
- Django - Django Rocks
- Django - How to Tango with Django
- Other Frameworks - Bottle
- Other Frameworks - Flask
现在检查下填充脚本是否填充了数据库。重启Django开发服务器,导航到管理接口,并检查是不是多了一些新分类和页面。如果你点击Page
,你看到类似图3的所有页面了么?
虽然写填充脚本会费些时间,但是如果你改变了模型,你会非常庆幸你写了它。当你更新模型的时候记得更新填充脚本——你不会想要它们之间互不一致。
5.9. 基本流程
目前我们已经介绍了Django模型的主要部分,现在是时候总结下整个过程了。我们将核心任务分成了不同的部分。
5.9.1. 建立数据库
在一个新Django工程中,你首先告诉Django打算使用的数据库(即,在setting.py中配置DATABASES
)。不这么干,Django不知道在哪里存储数据。你还可以启用管理接口来简化操作——注意,如果你不想,可以禁用。
5.9.2. 添加模型
添加模型的流程可以分为5个步骤。
- 首先,在Django应用的
models.py
文件中新建model(s)。
- 创建好模型,如果你使用管理接口,那么重新配置管理接口将模型包含进去。
- 通过命令
$ python manage.py syncdb
同步或者重新同步数据库。这会在数据库中为新模型创建必须的结构。
- 新建填充脚本,并运行。
注意syncdb
命令的使用事项。这个命令只用于添加新模型到数据库中|如果你想修改已有的模型,你必须重新创建数据库。
5.10. 练习
略
20131124@深圳 南山