假如, 我们在 views.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})
这个方法可用, 但很快一些问题将出现在你面前:
1.我们将数据库连接参数硬行编码于代码之中。 理想情况下,这些参数应当保存在 Django 配置中.

2.我们不得不重复同样的代码: 创建数据库连接、创建数据库游标、执行某个语句、然后关闭数据库。 理想情况下,我们所需要应该只是指定所需的结果

3.它把我们栓死在 MySQL 之上。 如果过段时间,我们要从 MySQL 换到 PostgreSQL,就不得不使用不同的数据库适配器(例如 psycopg 而不是MySQLdb ),改变连接参数,根据 SQL 语句的类型可能还要修改SQL 。 理想情况下,应对所使用的数据库服务器进行抽象,这样一来只在一处修改即可变换数据库服务器。 (如果你正在建立一个开源的Django应用程序来尽可能让更多人使用的话,这个特性是非常适当的。

数据库的配置 settings.py

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'my_db',
'USER': 'Leon',
'PASSWORD': '123',
'HOST': 'localhost',
'PORT': 3306,
}
}

设置好后, 可以通过 python manager.py shell 看看能否打开 shell 来判断是否连接成功.

Django模型

django 模型是用python代码形式表述的数据在数据库中的定义, 对数据层来说比如 create table 语句执行的是python代码而不是SQL.

Django 用模型在后台执行SQL代码并把结果用python数据结构来描述(完全抽象出了SQL代码)

Django 能够让你不写SQL语句, 而不是像常规模式 写会 java -> SQL -> java -> SQL

另外, 还有一个好处就是可以扩展到不同的数据库平台. 因为 表, 列的定义, 都是来自于 Django 的 models的同步.

缺点: python代码和数据库表的同步问题, 如果你修改了一个Django 模型, 你要自己来修改数据库来保证和模型同步. (如果是传统方法, 我们只要修改数据库一个地方就可以了)

提示: Django 提供了实用工具来从现有的数据库表自动扫描生成模型. 这对已有数据库来说, 非常便捷.

举例

我们来假定下面的这些概念、字段和关系:
一个作者有姓,有名及email地址。
出版商有名称,地址,所在城市、省,国家,网站。
书籍有书名和出版日期。 它有一个或多个作者(和作者是多对多的关联关系[many-to-many]), 只有一
个出版商(和出版商是一对多的关联关系[one-to-many],也被称作外键[foreign key])

在 models.py中

models_数据库

 每个数据类型是 django.db.models.Model 的子类, 它的父类Model包含所有必要的和数据库交互的方法.

每个模型相当于数据库表. 每个属性相当于一个字段. 属性名就是字段名, 它的类型(例如 CharField) 相当于数据库字典中的 varchar 类型, 例如 Publisher 这个模型, 它相当于在DB中创建了一个表:

create table publisher(

id number not null primary key,

name varchar(30) not null,

address varchar(30) not null,

city varchar(60) not null,

state_province varchar(30) not null,

country varchar(50) not null,

website varchar(200) not null);

每个数据库表对应一个类, 这个规则的例外情况是多对对关系,在我们的例子中, 有一个多对多字段, authors 表明一本书的有一个或多个作者, ManyToManyField, foreign key 类似这种类型, 个人都不推荐.

最后需要注意的是, 我们并没有显示的为每个模型定义任何主键, 除非你单独指明, 否则Django会自动为每个模型生成一个自增长的整数主键字段, 每个Django模型都要求有单独的主键 id.

模型安装

 python manage.py validate 验证模型的有效性 (没执行成功)

python manage.py sqlall first 没有执行成功, 其中 first 是 app 的名字, 并没有真正的创建表, 只是把创建表的语句打印出来

python manage.py syncdb 同步, 这才真正的创建表 (并不能讲模型的修改或删除同步到数据库)

基本数据访问

一旦你创建好了模型, 接下来就可以访问, 运行 python manage.py shell, 输入以下内容

models_python_02

save 方法是将对象保存到数据库中

而每创建一个对象, 相当于往 DB 中插入一条记录.

p1 = Publish.objects.create(name='Apress',...)  类似这种的定义方法, 可以直接写入DB, 不用再调用save()方法

当我们想要打印整个列表时, 我们没有得到我们想要的信息, 原因是程序无法把对象区分开来.

我们可以简单的解决这个问题, 只需要为 Publisher 类添加一个方法 __unicode__(), 告诉Python如何将对象以unicode的方式显示出来

比如在一个类中, 增加 

def __unicode__(self):

  return self.title    # 告诉Python, 输出什么.

当你修改这个对象的属性的值时, 实际上就相当于在做 update操作

p.name = 'Apress Publishing'    # update table set name = 'Apress Publishing' where id = '1'; 这个id是主键

数据过滤

filter(name ='Apress', state_province='CA') 类似 where 语句, 多条件也支持

name__contains ='press'   表示sql 语句时 name like ('%press%')

name__icontains 大小写无关

startwith, endwith, range 等很多

返回单个对象, 而不是列表, 用 get, 也就是一条记录

Publisher.objects.get(country='U.S.A'), 假如返回了多条, 会报错, 没查到也会返回异常, 所以, 你最好还是用 DoesNotExist

try:

  p = Publisher.objects.get(name='Apress')

except Publisher.DoesNotExist:

  print 'Apress isn't in the database yet.'

else:

  print 'Apress in the database'

排序, Publisher.objects.order_by('name', '-country')  # 前面带-号是倒排序的意思

内部类, class Meta, 你可以在任意一个模型类中使用 Meta类, 来设置一些与特定模型相关的选项. 

例如, 我们现在关注 ordering 这个选项. 如果你设置了这个选项, 那么除非你检索时特意额外的使用了 order_by(), 否则, Publisher对象的相关返回值都会默认的按照 name 字段排序.

class Meta:

  ordering = ['name']

链式查询 Publisher.objects.filter(country='U.S.A').order_by('-name')

这个有点类似 linux 的 shell, 前边一个命令的结果集(QuerySet)是后一个命令的参数.

限制返回的条数, Publisher.objects.order_by('name')[0], 因为返回的是一个 对象, 数据行的List, list[0], 就表示第一个对象, 也就是第一行

注意, 这个是可以切片的, 比如

Publisher.objects.order_by('name')[0:2]  # 这种切片不支持负索引. 其实虽然不支持, 但是我们自己可以变通,  order_by('-name') 就是一个变通的方法

有条件(除了id之外的)的 update语句, Publisher.objects.filter(id=52).update(name='Apress Publishing')

update()方法会返回一个整型数值, 表示受影响的记录条数.

删除, 一个道理, Publisher.objects.filter(country='USA').delete()

 

允许字段为空, 在设计字段时, email = models.EmailField(blank=True), 

Django 字段, 没有特殊说明的情况下, 全部默认为 Not NULL

如果你想让 日期和数字也可以有空值, 那么你必须同时制定 blank=True 和 Null=True

自定义字段标签. 类似comment, email = models.EmaiField(blank=True, verbose_name='e-mail')

MySql 数据类型 与 models 对应关系

varchar 对应 charField   (EmailField 是在 CharField 的基础上, 增加了判断 email 合法性的判断)  URLFild 也是

blob  BooleanField

int/integer      IntegerField   整数
double/float    FloatField
datetime  DateTimeField

Text   TextField  超大文本

ImageField/ FileField

Field选项(参数)

null  如果为真, 表示可以存储空值. 通常不用在字符的字段你上, 字符型字段如果没有值, 会返回空字符而不是Null.

blank 字段是否可以为空

choices   类似 check, 例如 SEX_CHOICES=('M', 'F')   也就是说, 字段的值, 只能在这里边选

default 缺省值

db_index  如果为 True, 会为字段创建索引

db_column 指定该列在数据库中的名字, 如果不指定自动采用model的字段名

editable, True/False  如果为假, admin 不能修改

unique, 是否有唯一性检查

verbose_name, 别名 类似 comment

 高级

添加一个字段的方法 (因为添加不能再同步了)

1. django类中添加一个属性, 然后运行 python mange.py sqlall books 来查看 create table语句

2. 根据 create table 语句, 直接到 DB 中, 添加该列

这样, 就添加字段成功了

删除字段也是一样, 需要分别在 Django 和 DB 进行两次删除. (一定要先修改 Django, 再修改DB)

执行原始SQL

有时候你会发现 Django数据库API带给你的只有这么多, 那你可以写一些自定义的SQL查询.可以通过 django.db.connection对象轻松实现. 它代表当前数据库连接. connection.cursor,得到游标对象, 然后使用 cursor.execute(sql, [params])来执行SQL语句, 使用cursor.fetchone()或者cursor.fetchall()返回记录集.

%s 会自动添加引号, 所以, 你不要为参数加引号, 参数什么就是什么.

而且貌似不需要关闭连接, 因为还有别的在用. 另外, 这个SQL语句肯定是在 models 中使用.

 多表查询

使用 prefetch_related