Models 层是 Django 框架中最强大的部分之一, 大大方便了 Web 层与数据层的交互。由于对 Model 层缺少系统理解,在使用 model Api 时经常需要查找文档, 在此做一次系统地整理。
本文主要是对 Django Model 文档的翻译,
文档地址
Models 层是 Django 框架中最强大的部分之一, 大大方便了 Web 层与数据层的交互。由于对 Model 层缺少系统理解,在使用 model Api 时经常需要查找文档, 在此做一次系统地整理。
本文主要是对 Django Model 文档的翻译,
文档地址
Model 层对象
一个model类对应数据库中的一张表, 类中的属性代表数据库中的各个字段。 类实例化后的对象, 代表数据库中的一条记录。
本文将基于下面的 models 对象展开, 由 Blog, Author, Entry 三个 models 组成。 Blog, Author 是两个独立的 model(表), 没有任何外键字段。 Entry 和 Blog 是多对一的关系, 通过外键关联; Entry 和 Author 是多对多关系。
假设 Blog 类所在目录为 mysite/blog/models.py, Author 类所在目录为 mysite/author/models.py, Entry 类所在目录为 mysite/entry/models.py
class
Blog
(models.Model):
name = models.CharField(max_length=
100)
tagline = models.TextField()
class
Author
(models.Model):
name = models.CharField(max_length=
200)
email = models.EmailField()
class
Entry
(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=
255) //外键
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author) // 多对多
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
entry = Entry.objects.get(pk=
1)
cheese_blog = Blog.objects.get(name=
'Cheddar Talk')
entry.blog = cheese_blog
entry.save()
joe = Author.objects.create(name=
'Joe')
entry.authors.add(joe)
john = Author.objects.create(name=
'john')
paul = Author.objects.create(name=
'paul')
ringo = Author.objects.create(name=
'ringo')
entry.authors.add(john, paul, ringo)
对数据库中对象的检索, 是通过 model Manage 来构造一个 QuerySet 对象来实现。每个 model 类都有一个
Manage
方法, Model 类通过 objects 来调用 Manage 方法。 model 对象中没有 objects 属性。QuerySet 对象是一个model 类对应的实例集合, 即数据库对应表的子集。
QuerySet 可以是 空(zero), 单个对象(one), 多个对象(many).
QuerySet 通过 Filters 方法来实现查询结果的过滤。 对于 SQL 来说, QuerySet 等同于 SELECT 声明, Filter 等同于 LIMIT, WHERE 声明。
检索所有对象
查找 model 类对应表中的所有对象 (数据), 是通过 all() 方法来实现, 其返回一个 QuerySet 对象。
上面所列的三个条件最终会整合成一条 SQL 语句去执行:
SELECT * FROM entry(表名) WHERE headline LIKE ‘What%’ AND NOT pub_date = ‘2017-3-28’ AND pub_date > ‘2017-3-10’
4、每个 filter 返回的对象都是不相关的
每次查询生成的 QuerySet 对象都是相互独立的, 可以保存或重复使用
q1 = Entry.objects.filter(headline__startwith=
'What')
q2 = q1.exclude(pub_data__gte=datetime.date.today())
q3 = q1.filter(pub_data__gte=datetime.date.today())
q = Entry.objects.filter(headline__startwith=
'What')
q = q.filter(pub_date__lte=datetime.date.today())
q = q.exclude(body_text__icontains=
'food')
print(q)
QuerySet 的其他方法
当进行数据库查询时,常用的也就是 all(), get(), filter() 和 exclude() 等方法。但是这些方法,无法完成一些复杂的查询方法。下面将介绍一些 QuerySet 的复杂的查询方法。
Limiting 查询
利用 Python Array 中的分片, 可以限制返回查询结果的数量。 其对应的 SQL 语法为 LIMIT 和 OFFSET。
返回结果为 QuerySet 对象
例如:
限制返回查询结果集中的前5组数据 (LIMIT 5)
Entry.objects.all()[
0:
1]
Entry.objects.all()[
0]
Entry.objects.all()[
0:
1].get()
Entry.objects.filter(pub_date__lte=datetime.date.today())
Entry.objects.filter(headline__iexact=
'cat Bites Dog')
Entry.objects.filter(blog__name=
'beatles blog')
Blog.objects.filter(entry__headline__contains=
'Lennon', entry__pub_date__year=
2013)
Blog.objects.filter(entry__headline__contains=
'Lennon').filter(entry__pub_date__year=
2013)
Entry.objects.filter(authors__name=F(
'blog__name'))
from datetime
import timedelta
Entry.objects.filter(mod_date__gt=F(
'pub_date') + timedelta(day=
3))
queryset = Entry.objects.all()
[entry
for entry
in Entry.objects.all()]
print(queryset[
5])
print(queryset[
5])
from django.db.models
import Q
entry = Entry.objects.filter(Q(headline__startswith=
'what') | Q(headline__startswith=
'who'))
Entry.objects.filter(Q(headline__startswith=
'what'), Q(pub_date=date(
2017,
3,
29)) | Q(pub_date=date(
2017,
3,
31)))
Entry.objects.filter(Q(pub_date=date(
2017,
3,
29)) | Q(pub_date=date(
2017,
3,
31)), headline__startswith=
'what')
Entry.objects.filter(headline__startswith=
'what', Q(pub_date=date(
2017,
3,
29)) | Q(pub_date=date(
2017,
3,
31)))
当 Django 删除一个数据时, 其默认或使用 SQL 的 CASCADE 删除模式, 即: 在父表上 delete 删除一条数据是,与之通过 ForeignKey 关联的子表中的数据也对应删除。
在 Django 中复制一条数据只需要将对应的 model 对象的 pk(id) 清除即可
blog = Blog(name=
'My blog', tagline=
'Blogging is easy')
blog.save()
blog.pk =
None
blog.save()
entry = Entry.objects.all()[
0]
auther_old = entry.authors.all()
entry.pk =
None
entry.save()
entry.authors.set(auther_old)
对象的对应关系
当在 model 定义是添加了 ForeignKey, OneToOneFiedl, ManyToMangField 的字段时, model 会自动生成相关 API 来获取相关数据。
One-To-Many 关系
1、正向获取
父表 to 子表
如果一个 model 包含有 ForeignKey 字段, 这个 model 的对象可以方便的获取与之关联的另一个 model 的对象。
例如: 获取 Entry 对象对应的 Blog 对象
e = Entry.objects.get(id=
3)
e.authors.all()
e.authors.count()
e.authors.filter(name__contains=
'John')
a = Author.objects.get(id=
5)
a.entry_set.all()
class
EntryDetail
(models.Model):
entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
details = models.TextField()
ed = EntryDetail.objects.get(pk=
3)
en.entry
e = Entry.objects.get(pk=
3)
e.entrydetail
e.entrydetail = ed2
e.save()
Entry.objects.filter(blog=b)
Entry.objects.filter(blog=b.id)
Entry.objects.filter(blog=
5)
做个标记: 下期整理 QuerySet 比较常用的 API
Model 层对象
一个model类对应数据库中的一张表, 类中的属性代表数据库中的各个字段。 类实例化后的对象, 代表数据库中的一条记录。
本文将基于下面的 models 对象展开, 由 Blog, Author, Entry 三个 models 组成。 Blog, Author 是两个独立的 model(表), 没有任何外键字段。 Entry 和 Blog 是多对一的关系, 通过外键关联; Entry 和 Author 是多对多关系。
假设 Blog 类所在目录为 mysite/blog/models.py, Author 类所在目录为 mysite/author/models.py, Entry 类所在目录为 mysite/entry/models.py
class
Blog
(models.Model):
name = models.CharField(max_length=
100)
tagline = models.TextField()
class
Author
(models.Model):
name = models.CharField(max_length=
200)
email = models.EmailField()
class
Entry
(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=
255) //外键
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author) // 多对多
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
entry = Entry.objects.get(pk=
1)
cheese_blog = Blog.objects.get(name=
'Cheddar Talk')
entry.blog = cheese_blog
entry.save()
joe = Author.objects.create(name=
'Joe')
entry.authors.add(joe)
john = Author.objects.create(name=
'john')
paul = Author.objects.create(name=
'paul')
ringo = Author.objects.create(name=
'ringo')
entry.authors.add(john, paul, ringo)
对数据库中对象的检索, 是通过 model Manage 来构造一个 QuerySet 对象来实现。每个 model 类都有一个
Manage
方法, Model 类通过 objects 来调用 Manage 方法。 model 对象中没有 objects 属性。QuerySet 对象是一个model 类对应的实例集合, 即数据库对应表的子集。
QuerySet 可以是 空(zero), 单个对象(one), 多个对象(many).
QuerySet 通过 Filters 方法来实现查询结果的过滤。 对于 SQL 来说, QuerySet 等同于 SELECT 声明, Filter 等同于 LIMIT, WHERE 声明。
检索所有对象
查找 model 类对应表中的所有对象 (数据), 是通过 all() 方法来实现, 其返回一个 QuerySet 对象。
上面所列的三个条件最终会整合成一条 SQL 语句去执行:
SELECT * FROM entry(表名) WHERE headline LIKE ‘What%’ AND NOT pub_date = ‘2017-3-28’ AND pub_date > ‘2017-3-10’
4、每个 filter 返回的对象都是不相关的
每次查询生成的 QuerySet 对象都是相互独立的, 可以保存或重复使用
q1 = Entry.objects.filter(headline__startwith=
'What')
q2 = q1.exclude(pub_data__gte=datetime.date.today())
q3 = q1.filter(pub_data__gte=datetime.date.today())
q = Entry.objects.filter(headline__startwith=
'What')
q = q.filter(pub_date__lte=datetime.date.today())
q = q.exclude(body_text__icontains=
'food')
print(q)
QuerySet 的其他方法
当进行数据库查询时,常用的也就是 all(), get(), filter() 和 exclude() 等方法。但是这些方法,无法完成一些复杂的查询方法。下面将介绍一些 QuerySet 的复杂的查询方法。
Limiting 查询
利用 Python Array 中的分片, 可以限制返回查询结果的数量。 其对应的 SQL 语法为 LIMIT 和 OFFSET。
返回结果为 QuerySet 对象
例如:
限制返回查询结果集中的前5组数据 (LIMIT 5)
Entry.objects.all()[
0:
1]
Entry.objects.all()[
0]
Entry.objects.all()[
0:
1].get()
Entry.objects.filter(pub_date__lte=datetime.date.today())
Entry.objects.filter(headline__iexact=
'cat Bites Dog')
Entry.objects.filter(blog__name=
'beatles blog')
Blog.objects.filter(entry__headline__contains=
'Lennon', entry__pub_date__year=
2013)
Blog.objects.filter(entry__headline__contains=
'Lennon').filter(entry__pub_date__year=
2013)
Entry.objects.filter(authors__name=F(
'blog__name'))
from datetime
import timedelta
Entry.objects.filter(mod_date__gt=F(
'pub_date') + timedelta(day=
3))
queryset = Entry.objects.all()
[entry
for entry
in Entry.objects.all()]
print(queryset[
5])
print(queryset[
5])
from django.db.models
import Q
entry = Entry.objects.filter(Q(headline__startswith=
'what') | Q(headline__startswith=
'who'))
Entry.objects.filter(Q(headline__startswith=
'what'), Q(pub_date=date(
2017,
3,
29)) | Q(pub_date=date(
2017,
3,
31)))
Entry.objects.filter(Q(pub_date=date(
2017,
3,
29)) | Q(pub_date=date(
2017,
3,
31)), headline__startswith=
'what')
Entry.objects.filter(headline__startswith=
'what', Q(pub_date=date(
2017,
3,
29)) | Q(pub_date=date(
2017,
3,
31)))
当 Django 删除一个数据时, 其默认或使用 SQL 的 CASCADE 删除模式, 即: 在父表上 delete 删除一条数据是,与之通过 ForeignKey 关联的子表中的数据也对应删除。
在 Django 中复制一条数据只需要将对应的 model 对象的 pk(id) 清除即可
blog = Blog(name=
'My blog', tagline=
'Blogging is easy')
blog.save()
blog.pk =
None
blog.save()
entry = Entry.objects.all()[
0]
auther_old = entry.authors.all()
entry.pk =
None
entry.save()
entry.authors.set(auther_old)
对象的对应关系
当在 model 定义是添加了 ForeignKey, OneToOneFiedl, ManyToMangField 的字段时, model 会自动生成相关 API 来获取相关数据。
One-To-Many 关系
1、正向获取
父表 to 子表
如果一个 model 包含有 ForeignKey 字段, 这个 model 的对象可以方便的获取与之关联的另一个 model 的对象。
例如: 获取 Entry 对象对应的 Blog 对象
e = Entry.objects.get(id=
3)
e.authors.all()
e.authors.count()
e.authors.filter(name__contains=
'John')
a = Author.objects.get(id=
5)
a.entry_set.all()
class
EntryDetail
(models.Model):
entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
details = models.TextField()
ed = EntryDetail.objects.get(pk=
3)
en.entry
e = Entry.objects.get(pk=
3)
e.entrydetail
e.entrydetail = ed2
e.save()
Entry.objects.filter(blog=b)
Entry.objects.filter(blog=b.id)
Entry.objects.filter(blog=
5)