第五章:数据库交换开发篇
一、简要描述:
Web 应用中,很多业务逻辑经常牵涉到与数据库的交互。 数据库驱动网站 在后台连接数据库服务器,从中取出一些数据,然后在 Web 页面用漂亮的格式展示这些数据。或者,站点也提供让访问者自行填充数据库的功能。
只有使用
1、简单数据查询
from django.shortcuts import render_to_response
import MySQLdb
def book_list(request):
db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost')
cursor = db.cursor()
cursor.execute('SELECT name FROM books ORDER BY name')
names = [row[0] for row in cursor.fetchall()]
db.close()
return render_to_response('book_list.html', {'names': names})
这种方法可以用,但是不是最理想的方法,在Web开放中是有很多数据操作类,如果每一个类都写数据连接,关闭那太繁琐了。
我们希望不重复同样的代码:创建数据库连接、创建数据库游标、执行某个语句、然后关闭数据库。
下介绍的内容中就可以解决这个问题,也是Django框架对Web开放的很好的支持。
MTV 开发模式
1、MVC:了解MTV之前我们还是先复习一下MVC吧。
Django 紧紧地遵循这种 MVC 模式,可以称得上是一种 MVC 框架
-
M ,数据存取部分,由django数据库层处理,本章要讲述的内容。
-
V ,选择显示哪些数据要及怎样显示的部分,由视图和模板处理。
-
C ,根据用户输入委派视图的部分,由 Django 框架通过按照 URLconf 设置,对给定 URL 调用合适的 python 函数来自行处理。
2、MTV:那到底什么是MTV呢?
模型(Model)、模板(Template)和视图(Views),Django 也被称为 MTV 框架 。
-
M 代表模型(Model),即数据存取层。该层处理与数据相关的所有事务:如何存取、如何确认有效性、包含哪些行为以及数据之间的关系等。
-
T 代表模板(Template),即表现层。该层处理与表现相关的决定:如何在页面或其他类型文档中进行显示。
-
V 代表视图(View),即业务逻辑层。该层包含存取模型及调取恰当模板的相关逻辑。你可以把它看作模型与模板之间的桥梁。
数据库配置
1、 缺省匹配
打开项目Mysite在根目录下可以看到“ settings.py”文件,找到DATABASES 配置如下:
DATABASES = {
'default': {
'ENGINE':'', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
代码描述:
DATABASE_ENGINE 数据库引擎设置
DATABASE_NAME 将数据库名称告知 Django 。如果使用 SQLite,请对数据库文件指定完整的文件系统路径。(例如 '/home/django/mydata.db' )。
DATABASE_USER 告诉 Django 用哪个用户连接数据库。如果用SQLite,空白即可。
DATABASE_PASSWORD 告诉Django连接用户的密码。SQLite 用空密码即可。
DATABASE_HOST 告诉 Django 连接哪一台主机的数据库服务器。如果数据库与 Django 安装于同一台计算机(即本机),可将此项保留空白。使用 SQLite ,也可保留空白。
2、数据库引擎设置
DATABASE_ENGINE 告诉Django使用哪个数据库引擎
数据库引擎设置
设置 数据库 适配器
postgresql PostgreSQL psycopg 版本 1.x,
http://www.djangoproject.com/r/python-pgsql/1/.
postgresql_psycopg2 PostgreSQL psycopg 版本 2.x,
http://www.djangoproject.com/r/python-pgsql/.
mysql MySQL MySQLdb ,
http://www.djangoproject.com/r/python-mysql/.
sqlite3 SQLite Python 2.5+ 内建。 其他, pysqlite ,
http://www.djangoproject.com/r/python-sqlite/.
ado_mssql SQL Server adodbapi 版本 2.0.1+, Microsoft SQL Server
http://www.djangoproject.com/r/python-ado/.
oracle Oracle cx_Oracle ,
http://www.djangoproject.com/r/python-oracle/.
3、测试数据库配置
启动了一个 Python 交互界面 : 运行 python manage.py shell 命令
输入下面这些命令来测试你的数据库配置:
>>> from django.db import connection
>>> cursor = connection.cursor()
如果没有显示什么错误信息,那么你的数据库配置是正确的.
如果显示错误则配置数据库失败,检查错误代码,常见错误:
错误信息:You havent set the DATABASE_ENGINE setting yet.
解决方案:设置正确的 DATABASE_ENGINE 配置
错误信息:Environment variable DJANGO_SETTINGS_MODULE is undefined.
解决方案:运行命令行 python manage.py shell 而不是 python .
错误信息:Error loading _____ module: No module named _____.
解决方案:你没有安装相关的数据库适配器 (例如, psycopg 或 MySQLdb ).
错误信息:_____ isnt an available database backend.
解决方案:设置正确的 DATABASE_ENGINE 配置也许是拼写错误?
错误信息:database _____ does not exist
解决方案:设置 DATABASE_NAME 配置到一个已有的数据库,或者使用 CREATE DATABASE 语句
创建数据库。
错误信息:role _____ does not exist
解决方案:修改 DATABASE_USER 配置到一个有效用户
错误信息:could not connect to server
解决方案:确认 DATABASE_HOST 和 DATABASE_PORT 设置是正确的,并确认服务器是在运行
的。
第一个数据交换应用程序
1、创建项目
转到mysite项目目录,执行命令创建books目录
python manage.py startapp books
查看books文件目录中的文件:
books/
__init__.py
models.py
views.py
2、定义数据模型
打开 models.py 并输入下面的内容:
# -*- coding:utf-8 -*-
from django.db import models
from django.contrib import admin
class Publisher(models.Model):
name = models.CharField(max_length=30,blank=True)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province= models.CharField(max_length=30)
country=models.CharField(max_length=50)
website=models.URLField()
def __unicode__(self):
return self.name
#默认排序设置
#class Meta:
# ordering = ["name"]
#Admin 声明标志了该类有一个管理界面'''
class Admin:
pass
class Author(models.Model):
salutation=models.CharField(max_length=10)
first_name=models.CharField(max_length=30)
last_name=models.CharField(max_length=40)
email=models.EmailField(max_length=30)
#headshot = models.ImageField(upload_to='/tmp')
def __unicode__(self):
return '%s %s' % (self.first_name, self.last_name)
#Admin 声明标志了该类有一个管理界面'''
class Admin:
pass
class Book(models.Model):
title=models.CharField(max_length=100)
authors=models.ManyToManyField(Author)
publisher=models.ForeignKey(Publisher)
publication_date=models.DateField()
num_page =models.IntegerField(blank=True,null=True)
def __unicode__(self):
return 'Book name :%s' % self.title
模型安装
再次编辑 settings.py 文件, 找到 INSTALLED_APPS 设置 ,INSTALLED_APPS 告诉 Django 项目哪些 app 处于激活状态,
缺省情况下如下所示:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
)
把INSTALLED_APPS 设置中四个设置前面加#临时注释起来,
改缺省的 MIDDLEWARE_CLASSES 和 TEMPLATE_CONTEXT_PROCESSORS 设置,都注释起来。然后添加 'mysite.books' 到 INSTALLED_APPS 列表,现在看起来是这样:
MIDDLEWARE_CLASSES = (
# 'django.middleware.common.CommonMiddleware',
# 'django.contrib.sessions.middleware.SessionMiddleware',
# 'django.contrib.auth.middleware.AuthenticationMiddleware',
# 'django.middleware.doc.XViewMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = ()
#...
INSTALLED_APPS = (
#'django.contrib.auth',
#'django.contrib.contenttypes',
#'django.contrib.sessions',
#'django.contrib.sites',
'mysite.books',
)
校验模型的有效性:
python manage.py validate
0 errors found 消息:表示一切正常
否则就是错误,检查数据模型是否正确。
生成SQL语句:
python manage.py sqlall books
运行命令的结果是这样的:
BEGIN;
CREATE TABLE "books_publisher" (
"id" serial NOT NULL PRIMARY KEY,
"name" varchar(30) NOT NULL,
"address" varchar(50) NOT NULL,
"city" varchar(60) NOT NULL,
"state_province" varchar(30) NOT NULL,
"country" varchar(50) NOT NULL,
"website" varchar(200) NOT NULL
);
CREATE TABLE "books_book" (
"id" serial NOT NULL PRIMARY KEY,
"title" varchar(100) NOT NULL,
"publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"),
"publication_date" date NOT NULL
);
CREATE TABLE "books_author" (
"id" serial NOT NULL PRIMARY KEY,
"salutation" varchar(10) NOT NULL,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(40) NOT NULL,
"email" varchar(75) NOT NULL,
"headshot" varchar(100) NOT NULL
);
CREATE TABLE "books_book_authors" (
"id" serial NOT NULL PRIMARY KEY,
"book_id" integer NOT NULL REFERENCES "books_book" ("id"),
"author_id" integer NOT NULL REFERENCES "books_author" ("id"),
UNIQUE ("book_id", "author_id")
);
CREATE INDEX books_book_publisher_id ON "books_book" ("publisher_id");
COMMIT;
代码描述:
A、自动生成的表名是app名称( books )和模型的小写名称( publisher , book , author )的组合
B、Django会站点添加一个ID主键,是可以修改的。
C 、按约定规则,Django添加的"_id"后缀到外键字段名。
D、外键是用 REFERENCES 语句明确定义的。
E、这些 CREATE TABLE 语句会根据你的数据库而作调整,这样象数据库特定的一些字段例如: auto_increment (MySQL), serial (PostgreSQL), integer primary key (SQLite) 可以自动处理。
同步数据库:
python manage.py syncdb
你将会看到这样的内容:
Creating table books_publisher
Creating table books_book
Creating table books_author
Installing index for books.Book model
重启服务器:
重启Web服务器
python manage.py runserver
数据访问类
python manage.py shell 进入
1、获取所以数据
>>> from books.models import Publisher
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: lhj-588>, <Publisher: loker>]
2、插入数据
>>> from books.models import Publisher
>>>p = Publisher(name='Apress',
... address='2855 Telegraph Ave.',
... city='Berkeley',
... state_province='CA',
... country='U.S.A.',
... website='http://www.apress.com/')
>>> p.save()
转换成SQL:
INSERT INTO book_publisher
(name, address, city, state_province, country, website)
VALUES
('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA',
'U.S.A.', 'http://www.apress.com/');
3、修改数据
>>> from books.models import Publisher
>>>p = Publisher(name='Apress'
,... address='2855 Telegraph Ave.'
,... city='Berkeley'
,... state_province='CA'
,... country='U.S.A.'
,... website='http://www.apress.com/')
>>> p.save()
>>> p.id
3
>>> p.name ='apress Publishing'
>>> p.save()
后面执行的 save() 相当于下面的SQL语句:
UPDATE book_publisher SET
name = 'Apress Publishing',
address = '2855 Telegraph Ave.',
city = 'Berkeley',
state_province = 'CA',
country = 'U.S.A.',
website = 'http://www.apress.com'
WHERE id = 52;
4、过滤数据 filter()
>>> from books.models import Publisher
>>>Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress Publishing>]
相当于SQL语句:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
WHERE country = 'U.S.A.' AND state_province = 'CA';
5、获取单个对象
>>> from books.models import Publisher
>>>Publisher.objects.get(name="Apress Publishing")
[<Publisher: Apress Publishing>]
如果查询出多个对象,则会导致抛出异常。
6、数据排序 order_by
>>> from books.models import Publisher
>>>Publisher.objects.order_by("name")
[<Publisher: Apress Publishing>, <Publisher: Addison-Wesley>, <Publisher: O'Reilly>]
相当于SQL:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
ORDER BY name;
可以指定逆向排序
Publisher.objects.order_by("-name")
7、限制返回的数据
>>>from books.models import Publisher
>>>Publisher.objects.all()[0]
<Publisher: Addison-Wesley>
>>>Publisher.objects.all()[0:2]
[<Publisher: Addison-Wesley>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>]
8、删除对象.delete()
>>>from books.models import Publisher
>>>p = Publisher.objects.get(name="Addison-Wesley")
>>> p.delete()
>>> Publisher.objects.all()
[<Publisher: Apress Publishing>, <Publisher: O'Reilly>]
>>>publishers.delete()
>>> Publisher.objects.all()
[]
修改数据库表结构
你需要查看 manage.py sqlall 的执行结果
同用步骤:
A、修改数据模型
B、同步数据库:执行python manage.py syncdb
C、重启服务器:执行python manage.py runserver
先修改在开发环境而不是发布服务器上修改
1、添加字段
在开发环境中执行下面的步骤:
-
把这个字段添加到你的模型中.
-
运行 manage.py sqlall [yourapp] 会看到模型的新的 CREATE TABLE 语句。注意新的字段的列定义。
-
启动您的数据库交互shell(也就是 psql 或 mysql , 或者您也可以使用 manage.py dbshell )。 执行一个 ALTER TABLE 语句,添加您的新列
4. (可选)用 manage.py shell 动ython交互式shell,并通过引入模型并选择表验证新的字段已被正确添加(比如, MyModel.objects.all()[:5] )。
然后在发布服务器上执行下面的步骤:
-
启动你的数据库的交互式命令行;
-
执行 ALTER TABLE 语句,也就是在开发环境中第3步执行的语句;
-
添加字段到你的模型中。如果你在开发时使用了版本控制系统并checkin了你的修改,现在可以更新代码到发布服务器上了(例如,使用Subverison的话就是 svn update )。
-
重启Web服务器以使代码修改生效
2、删除字段
从模型里删除一个字段可要比增加它简单多了。删除一个字段仅需要做如下操作:
从你的模型里删除这个字段,并重启Web服务器。
使用如下面所示的命令,从你的数据库中删掉该列:
3、删除 Many-to-Many 字段
因为many-to-many字段同普通字段有些不同,它的删除过程也不一样:
删除掉你的模型里的 ManyToManyField ,并且重启Web服务器。
使用如下面所示的命令,删除掉你数据库里的many-to-many表:
DROP TABLE books_books_publishers;
4、删除模型
完全删除一个模型就像删除一个字段一样简单。删除模型仅需要做如下步骤:
将此模型从你的 models.py 文件里删除,并且重启Web服务器。
使用如下的命令,将此表从你的数据库中删除:
DROP TABLE books_book;