配置数据库:
settings 文件内:
DATABASES
=
{
'
default
'
: {
'
ENGINE
'
:
'
django.db.backends.postgresql_psycopg2
'
,
'
NAME
'
:
'
mydatabase
'
,
'
USER
'
:
'
mydatabaseuser
'
,
'
PASSWORD
'
:
'
mypassword
'
,
'
HOST
'
:
'
127.0.0.1
'
,
'
PORT
'
:
'
5432
'
,
}
}
如果是 SQLite,则只需填写 engine 和 name,SQLite 的 name 应当包含可靠路径(因为没有 server):
DATABASES
=
{
'
default
'
: {
'
ENGINE
'
:
'
django.db.backends.sqlite3
'
,
'
NAME
'
:
'
mydatabase
'
,
}
}
测试数据库配置:
>>>
from
django.db
import
connection
>>>
cursor
=
connection.cursor()
创建表
django 的 ORM 示例,定义在 app 下的 models 文件内,具体支持的字段参考官方文档:
from
django.db
import
models
class
Book(models.Model):
title
=
models.CharField(max_length
=
100
)
authors
=
models.ManyToManyField(Author)
publisher
=
models.ForeignKey(Publisher)
publication_date
=
models.DateField()
django 使用额外一张单独的表来管理多对多联系。
部署模型
在部署模型前,首先应保证相应的 app 是已安装状态,这在 settings 文件内的 INSTALLED_APPS 字段内进行设置。
验证模型有效性:
python manage.py validate
生成 CREAT TABLE 语句(打印出来给你看看,并不执行):
python manage.py sqlall books
这里的 books 是 app 的名称。运行后输出如下:
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_author" (
"id" serial
NOT
NULL
PRIMARY
KEY
,
"first_name"
varchar
(
30
)
NOT
NULL
,
"last_name"
varchar
(
40
)
NOT
NULL
,
"email"
varchar
(
75
)
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") DEFERRABLE INITIALLY DEFERRED,
"publication_date" date
NOT
NULL
)
;
CREATE
TABLE
"books_book_authors" (
"id" serial
NOT
NULL
PRIMARY
KEY
,
"book_id"
integer
NOT
NULL
REFERENCES
"books_book" ("id") DEFERRABLE INITIALLY DEFERRED,
"author_id"
integer
NOT
NULL
REFERENCES
"books_author" ("id") DEFERRABLE INITIALLY DEFERRED,
UNIQUE
("book_id", "author_id")
)
;
CREATE
INDEX
"books_book_publisher_id"
ON
"books_book" ("publisher_id");
COMMIT
;
注意:
- 这里自动生成的表名是:app名称( books )和模型的小写名称 ( publisher , book , author )的组合。除非你显式指定一个表名。
- Django为每个表格自动添加加了一个 id 主键, 你可以重新设置它。
- 按约定,Django添加 "_id" 后缀到外键字段名,这个同样是可自定义的
- 外键是用 REFERENCES 语句明确定义的(books 的 publisher 外键)
- 这些 CREATE TABLE 语句会根据你的数据库而作调整
同步数据库(仅添加,不会修改和删除表):
python manage.py syncdb
INSERT & UPDATE:
在 python manage.py shell 命令行内执行 INSERT 操作的方法是实例化一个模型对象,并调用其 .save() 方法
>>>
from
books.models
import
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() 方法在用于 UPDATE 功能时,实际执行的是更新整行而不仅是修改过的属性。这可能会引起竞态条件,如果想只更新一个属性,应当调用结果集的 .update() 方法:
>>>
Publisher.objects.filter(id
=
52
).update(name
=
'
Apress Publishing
'
)
update() 方法返回一个整数,表示受影响的行数。
DELETE:
.delete() 方法与 .update() 类似,都是作用于结果集的方法。但出于安全考虑,在删除表中所有元组时,需要显示调用 .all() 方法:
>>>
Publisher.objects.delete()
Traceback (most recent call last):
File
"
<console>
"
, line
1
,
in
<
module
>
AttributeError:
'
Manager
'
object has no attribute
'
delete
'
>>>
Publisher.objects.all().delete()
SELECT:
如果想 print 出 Publisher 对象的内容,需要在定义模型时写好 __str__() 方法。
>>>
publisher_list
=
Publisher.objects.all()
>>>
publisher_list
[
<
Publisher: Publisher object
>
,
<
Publisher: Publisher object
>
]
WHERE:
>>>
Publisher.objects.filter(name
=
'
Apress
'
[,
***
])
[
<
Publisher: Apress
>
]
LIKE:
注意这里是双下划线 __contains
>>>
Publisher.objects.filter(name__contains
=
"
press
"
)
[
<
Publisher: Apress
>
]
filter() 返回的总是一个容器对象,这个对象实现了列表的操作方法(一如既往不包括负索引),因此总是可以使用比如 for 循环来迭代其中的元素。对应的有一个 get() 方法,这个方法要求满足条件的元素有且只有一个,否则引发异常。
给结果排序:
>>>
Publisher.objects.order_by(
"
state_province
"
,
"
address
"
)
第二个参数仅在第一个参数相同时起作用,排序还可以在属性前加“-”来实现逆序:
>>>
Publisher.objects.order_by(
"
-name
"
)
.ordered_by() 可作用于结果查询结果对象集,所以 filter() 返回的结果也可以支持。
或者,直接在模型定义的地方指定默认排序方式:
class
Publisher(models.Model):
name
=
models.CharField(max_length
=
30
)
.
.
.
class
Meta:
ordering
=
[
'
name
'
]
访问外键(Foreign Key)值:
当访问外键字段时,会得到相应的模型对象:
>>>
b
=
Book.objects.get(id
=
50
)
>>>
b.publisher
<
Publisher: Apress Publishing
>
>>>
b.publisher.website
u
'
http://www.apress.com/
'
而当通过外键反向追溯时,则会获得一个模型对象的 QuerySet,这个对象与前面一样也支持过滤和分切操作。实现这类访问使用的属性名是由模型名称的小写 + _set 组成的:
>>>
p
=
Publisher.objects.get(name
=
'
Apress Publishing
'
)
>>>
p.book_set.all()
[
<
Book: The Django Book
>
,
<
Book: Dive Into Python
>
, ...]
>>>
p.book_set.filter(name__icontains
=
'
django
'
)
[
<
Book: The Django Book
>
,
<
Book: Pro Django
>
]
访问多对多值:
多对多和外键工作方式相同,只不过处理的是QuerySet而不是模型实例:
>>>
b
=
Book.objects.get(id
=
50
)
>>>
b.authors.all()
[
<
Author: Adrian Holovaty
>
,
<
Author: Jacob Kaplan
-
Moss
>
]
>>>
b.authors.filter(first_name
=
'
Adrian
'
)
[
<
Author: Adrian Holovaty
>
]
>>>
b.authors.filter(first_name
=
'
Adam
'
)
[]
反向查询也可以。 要查看一个作者的所有书籍,使用author.book_set ,就如这样:
>>>
a
=
Author.objects.get(first_name
=
'
Adrian
'
, last_name
=
'
Holovaty
'
)
>>>
a.book_set.all()
[
<
Book: The Django Book
>
,
<
Book: Adrian
'
s Other Book>]
更改数据库模式(DB schema):
先前提到过,syncdb 命令只添加新表,并不会把已有模型的更新同步到数据库中。实际上,django 对已有 模型 与 数据库 之间的对应关系仅作最低限度的检查——即:模型中的字段在数据库中必须有,否则会引发运行时错误(在用户进行查询的时候);至于数据库中是否存在模型里并未定义的字段,django 并不关心,因为数据库中多余的字段并不影响 django 依据模型做正常的查询。(django 在做 orm 到 sql 语句的转化时,总是会明确指出要查询的字段)
基于这种逻辑,想要修改数据库模式应该采用的方法就是:在不引发运行时错误的前提下,按特定顺序分别修改数据库和模型。具体顺序为:
- 添加字段时:先在开发者环境下修改模型,并通过 sqlall 命令查看修改模型需要使用的 sql 语句,修改数据库与模型并测试通过。然后去部署环境提交这条语句以修改数据库,之后在部署环境修改模型,最后重启 server,使修改生效。这里利用 sqlall 刻意使用了 django 生成的 sql 语句,但这并不是必须的,这只是一个好习惯,如果命令简单,也完全可以自己写这条 sql 命令,但在开发环境下进行测试还是不可少的
- 添加非 NULL 字段时:因为新添加的字段总是空的,所以如果需要添加非 NULL 字段,就要先添加如 IntegerField(blank=True,null=True) 这样的允许空值字段,然后给他们赋值,再把它们改成非 NULL 字段。
- 删除字段时:这时的操作顺序与添加字段相反,必须先修改模型,再修改数据库。
- 删除多对多联系时:先在模型中删除多对多字段,然后在数据库中删除多对多关系表(前面提到过,django 用一张单独的表管理多对多联系)。语句形如:DROP TABLE books_book_authors; (最前面的 books 是 app 名)
- 删除模型时:从 models 文件中删除模型,然后从数据库中删除表:DROP TABLE books_book; 另外,如果其他表有指向这张表的外键,那么你得先把那些表删了...
Managers
在形如 Book.objects.all() 的语句中,objects 作为 models.Model 类的一个特殊属性,他是 models.Manager 的实例。有些时候我们可以通过自定义这个属性来实现一些特别的方法,或修改 manager 返回的 QuerySets 。
增加额外的Manager方法:
这需要子类化一个 Manager 对象,再把它绑定到具体的模型中,比如:
#
models.py
from
django.db
import
models
#
... Author and Publisher models here ...
class
BookManager(models.Manager):
def
title_count(self, keyword):
return
self.filter(title__icontains
=
keyword).count()
class
Book(models.Model):
title
=
models.CharField(max_length
=
100
)
authors
=
models.ManyToManyField(Author)
publisher
=
models.ForeignKey(Publisher)
publication_date
=
models.DateField()
num_pages
=
models.IntegerField(blank
=
True, null
=
True)
objects
=
BookManager()
def
__unicode__
(self):
return
self.title
有了这个manager,我们现在可以这样做:
>>>
Book.objects.title_count(
'
django
'
)
4
>>>
Book.objects.title_count(
'
python
'
)
18
修改初始Manager QuerySets:
manager的基本QuerySet返回系统中的所有对象。 例如,`` Book.objects.all()`` 返回数据库book中的所有书本。我们可以通过覆盖Manager.get_query_set()方法来重写manager的基本QuerySet。 get_query_set()按照你的要求返回一个QuerySet。
from
django.db
import
models
#
First, define the Manager subclass.
class
DahlBookManager(models.Manager):
def
get_query_set(self):
return
super(DahlBookManager, self).get_query_set().filter(author
=
'
Roald Dahl
'
)
#
Then hook it into the Book model explicitly.
class
Book(models.Model):
title
=
models.CharField(max_length
=
100
)
author
=
models.CharField(max_length
=
50
)
#
...
objects
=
models.Manager()
#
The default manager.
dahl_objects
=
DahlBookManager()
#
The Dahl-specific manager.
在这个示例模型中,Book.objects.all()返回了数据库中的所有书本,而Book.dahl_objects.all()只返回了Roald Dahl的书。
这个例子也说明了另外一件事情,就是一个模型可以有多个 manager 属性。你只需要给他们做好命名就可以了(不要再用 objects)。
注意:django 会把模型中定义的第一个 manager 作为默认 manager 使用,如果你重写了任何一个 manager 的话。所以当你给模型添加 manager 的时候,一定记得在最前面把 models.Manager 绑定给 objects 。
模型方法:
模型方法就是模型里定义的方法,跟普通类里定义的方法没什么不同。
执行原始 SQL 查询:
使用 DB-API 即可。
来源:oschina
链接:https://my.oschina.net/u/660175/blog/214806