web应用中,主观逻辑(视图处理)经常牵涉与数据库的交互。数据库驱动网站在后台连接数据库,从中取数据,然后甩漂亮界面展现在web端。许多复杂的网站都提供以上两种功能的结合(如Amazon.com),而Python天生具备简单强大的数据库查询执行方法,很适合开发这类数据库驱动网站。
他就是下面介绍的Django数据库层!
【 硬 编 码 链 接 数 据 库 】
cat ~/HelloWorld/HelloWorld/view.py
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})
弊端:此方法虽可用,但是我们将参数配置直接硬编码到视图函数,显然犯了前两节相同的错误;如果我们改一个参数、改一种数据库、换个执行语句等等,都会引起大范围的改动。
那我们能不能像上节那样创建模板,其实django提供了更简单直接的方式:数据库API
===============================================================================================
MVC架构模式、MTV 开发模式
Django 设计遵循松耦合原则,修改某部分不影响其他部分。视图函数中通过了模板系统将业务逻辑和表现逻辑分隔,数据库层也应如此。
MVC 架构模式:即数据存取逻辑(model)、表现逻辑(view)、业务逻辑(controller)的组合
其中 C 由框架自行处理,django更关注的是模型(model)、模板(template)、视图(views),也被称MTV框架
M:数据存取,处理与数据相关所有事务;
T:表现层,处理与表现相关的决定,比如页面如何显示;
V:视图,处理存取模型和调取模板的逻辑,可看做模型与模板的桥梁。
注: django认为视图用来展现数据,控制器是如何展示;其他框架认为控制器用来展现数据,视图决定如何展现。
================================================================================================
上面所说的数据库API,其实就是更改django配置文件,通过配置文件的接口进数据库。
数据库 | DATABASE_ENGINE | 适配器 |
PostgreSQL | postgresql | http://www.djangoproject.com/r/python-pgsql/1/ |
PostgreSQL | postgresql_psycopg2 | http://www.djangoproject.com/r/python-pgsql/ |
MySQL | mysql | http://www.djangoproject.com/r/python-mysql/ |
SQLite | sqlite3 | http://www.djangoproject.com/r/python-sqlite/ |
Oracle | oracle | http://www.djangoproject.com/r/python-oracle/ |
vim ~/HelloWorld/HelloWorld/settings.py DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘: ‘django‘, ‘USER‘: ‘django‘, ‘PASSWORD‘: ‘django123‘, ‘HOST‘:‘localhost‘, ‘PORT‘:‘3306‘, } }
之后去数据库建一个django库,并给django用户赋值。然后测试一下(没有报错信息即配置成功,并能链接到mysql的django库了,关于django报错信息,请参考下一节):
启动shell界面:python manage.py shell
>>> from django.db import connection
>>> cursor = connection.cursor()
【应用程序app 与 模型model.py】
第 一 个 app
Django规定:如果使用了django数据库层(或模型),必须要创建django app,把模型放在里面;应用程序app是项目project组成部分。
python manage.py startapp mysql_django #创建mysql_django app
创建好app,将app加入到HelloWorld project中
vim ~/HelloWorld/HelloWorld/settings.py INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ** ‘mysql_django‘, #逗号结尾,也可用点语法 HelloWorld.mysql_django ]
第 一 个 模 型
其实django模型就是以python代码表述数据库中表结构
vim ~/HelloWorld/mysql_django/models.py from django.db import models class Publisher(models.Model): #CREATE TABLE "books_publisher"("id" serial NOT NULL PRIMARY KEY, name = models.CharField(max_length=30) #"name" varchar(30) NOT NULL, address = models.CharField(max_length=50) #"address" varchar(50) NOT NULL, city = models.CharField(max_length=60) #"city" varchar(60) NOT NULL, state_province = models.CharField(max_length=30) #"state_province" varchar(30) NOT NULL, country = models.CharField(max_length=50) #"country" varchar(50) NOT NULL, website = models.URLField() #"website" varchar(200) NOT NULL ); class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField()
代码解读:
1、首先每个数据模型都是django.db.models.Model的子类,父类Model包含所有与数据库交互的必要方法;
2、每个模型相当于数据库表,每个属性即字段,类型(CharField)相当于字段类型(varchar)
3、Publisher举例,python语法即等于右边的数据库语法。
4、定义了出版商、作者、书籍的一些内容。
当完成以上模型建表后,并将其app加入到了项目,接下来就开始执行建表了
a、检查语法错误(django1.9.0版本以下用 python manage.py validate)
python manage.py check
b、生成数据库迁移文件(在app下的migrations下生成0001文件,更改后执行,生成0002....迁移文件)
python manage.py makemigrations mysql_django
c、同步数据库(老版本用python manage.py syncdb,即把迁移文件转换语法同步数据库[库名app名_类名])
python manage.py migrate
d、转换成 SQL 语言(老版本 python manage.py sqlall mysql_django,查看转换后的mysql语法)
python manage.py sqlmigrate mysql_django 0001
【Python 与 数 据 库 API】
进入:python manage.py shell
>>> from mysql_django.models import Publisher #导入Publisher模型类
>>> p1 = Publisher(name=‘Apress‘, address=‘2855 Telegraph Avenue‘,
... city=‘Berkeley‘, state_province=‘CA‘, country=‘U.S.A.‘,
... website=‘http://www.apress.com/‘)
>>> p1.save() #调用了save()方法,才能真正将p1插入数据库
>>> p2 = Publisher.objects.create(name="O‘Reilly",
... address=‘10 Fawcett St.‘, city=‘Cambridge‘,
... state_province=‘MA‘, country=‘U.S.A.‘,
... website=‘http://www.oreilly.com/‘) #objects.create()方法可直接将数据插入数据库
>>> publisher_list = Publisher.objects.all() #从数据库取出出版商信息==select
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
插入两个数据后,讲道理Publisher.objects.all()方法会取出Publisher类的对象,但是却没有得到有用信息;
解决此问题:要为Publisher对象添加一个__unicode__()方法,他告诉python将对象以unicode方式显示,如下:
vim ~/HelloWorld/mysql_django/models.py from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) ...................... website = models.URLField() ** def __unicode__(self): ** return self.name class Author(models.Model): ......................... ** def __unicode__(self): ** return u‘%s %s‘ % (self.first_name, self.last_name)** class Book(models.Model): ......................... ** def __unicode__(self): ** return self.title
============================================================================================
unicode对象 是能处理上百万不同类的字符串的python字符串。普通的python字符串是经过编码的,穿插调用的话就会出现常见的???等乱七八糟的字符,这就是编码的问题;而unicode对象没有编码,使用它可以不用考虑编码的问题。所以请确保每个模型都定义了__unicode__()方法。
关于unicode:http://www.joelonsoftware.com/articles/Unicode.html
再次进入shell解释器内,试验:>>> publisher_list
[<Publisher: Apress>, <Publisher: O‘Reilly>]
============================================================================================
1、数据查看、过滤操作:
>>> Publisher.objects.filter(name=‘Apress‘)
[<Publisher: Apress>] #filter == where name=‘Apress‘
>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>] #逗号转换成了 and
>>> Publisher.objects.filter(name__contains="press")
[<Publisher: Apress>] #__contains = where name LIKE ‘%press%‘;
>>> Publisher.objects.get(name="Apress")
<Publisher: Apress> #get()方法获取单个对象,filter()函数返回一个记录集(列表)
(icontains[大小写无关的LIKE]、startwith/endswith、range[BETWEEN])
2、数据排序操作:
>>> Publisher.objects.order_by("name")
[<Publisher: Apress>, <Publisher: O‘Reilly>] #按字母排序
>>> Publisher.objects.order_by("state_province", "address")
[<Publisher: Apress>, <Publisher: O‘Reilly>] #第一个字段相同,按第二个排序
>>> Publisher.objects.order_by("-name")
[<Publisher: O‘Reilly>, <Publisher: Apress>] #-号,表示逆向排序
vim ~/HelloWorld/mysql_django/models.py class Publisher(models.Model): def __unicode__(self): return self.name ** class Meta: ** ordering = [‘name‘] #Meta类,默认会以name字段进行排序
3、连锁查询:
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: O‘Reilly>, <Publisher: Apress>] #检索country="U.S.A."降序排列
>>> Publisher.objects.order_by(‘name‘)[0:2] #取数据的特定子集=offset 0 limit 2,查询语句也可以加
>>> Publisher.objects.order_by(‘name‘)[0] #[0]=limit 1;不支持负索引[-1],但可用降序[0]实现
<Publisher: Apress>
4、增加更改操作:(name、save、id、update)
添加数据:>>> p3 = ....name=‘Apress‘ ...
获取数据:>>> p2 = Publisher.objects.get(name="Apress")
更改数据:>>> p2.name = ‘Apress Publishing‘
保存数据:>>> p2.save() #他会update此id全部字段,不只是name字段;也有轻量级更改的方法。
看主键id:>>> p2.id #我们可根据get到的数据查id,也可直接进数据库查
更改数据:>>> Publisher.objects.filter(id=1).update(name=‘Apress Publishing‘)
批量更改:>>> Publisher.objects.all().update(country=‘USA‘) #返回数值即更改的条数
5、删除命令操作:
获取数据:>>> p = Publisher.objects.get(name="O‘Reilly") #先得到数据再删除
删除数据:>>> p.delete()
直接删除:>>> Publisher.objects.filter(country=‘USA‘).delete() #删除所有country=‘USA‘的
删除全部:>>> Publisher.objects.all().delete() #不加all()方法删除不了
查看数据:>>> Publisher.objects.all()
当然,以上的操作都是直接在shell解释器中操作,我们也可以写到视图函数中,页面化查看。
-------------------------------------------------------------------------------------------------