Django基础之模型层

内容概要

  • 查询关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    MySQL
    select
    from
    where
    group by
    having
    order by
    distinct
    limit
    regexp
    # SQL语句内也支持写流程控制
    Django ORM
  • 神奇的双下线查询

  • 多表查询

    1
    2
    3
    4
    5
    子查询
    基于对象的跨表查询
    连表操作
    基于双下划线的跨表查询
    ps:ORM远比SQL语句简单
  • 分组与聚合

  • F与Q查询

  • ORM查询优化(only与defer…)

  • ORM字段补充

内容详细

关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
   # 增     1.create()
# models.Books.objects.create(title='三国演义',price=456.23)
# models.Books.objects.create(title='水浒传',price=876.45)
# models.Books.objects.create(title='聊斋志异',price=123.69)
# models.Books.objects.create(title='草堂笔记',price=456.96)

# 查 2.all()
# res = models.Books.objects.all()
# print(res) # QuerySet对象
# print(res.query) # 只要是QuerySet对象就可以点query查看内部SQL语句

# 查 3.filter()
# res1 = models.Books.objects.filter() # pk特指当前表的主键字段
# print(res1) # QuerySet对象
# print(res1.query)
# print(res1.first()) # 获取列表中第一个数据对象
# print(res1.last()) # 获取列表中最后一个数据对象

# 4.values与5.values_list
# res2 = models.Books.objects.values('title','price')
# print(res2) # QuerySet对象 可以看成列表套字典
# print(res2.query)

# res3 = models.Books.objects.values_list('title','price')
# print(res3) # QuerySet对象 可以看成列表套元祖
# print(res3.query)

# 6.查 get() 不推荐使用
# res4 = models.Books.objects.get(pk=1)
# print(res4) # 数据对象
# res5 = models.Books.objects.get(pk=100)
# print(res5) # 数据对象
# res6 = models.Books.objects.filter(pk=100)
# print(res6) # 数据对象

# 7.取反 exclude()
# res7 = models.Books.objects.exclude(pk=1)
# print(res7) # QuerySet
# print(res7.query)


# 8.排序 order_by() 默认是升序(asc) 字段前面加负号降序(desc)
# res8 = models.Books.objects.order_by('price')
# res8 = models.Books.objects.order_by('-price')
# select * from books order by price desc,price asc;
# res8 = models.Books.objects.order_by('-price','price')
# print(res8) # QuerySet对象
# print(res8.query)


# 9.反转 reverse() 必须先有顺序才可以反转
# res9 = models.Books.objects.all()
# res9 = models.Books.objects.order_by('price').reverse()
# print(res9)

# 10.去重 distinct()
# res10 = models.Books.objects.all().distinct()
# res10 = models.Books.objects.values('title','price').distinct()
# print(res10)

# 11.计数 count()
# res11 = models.Books.objects.count()
# print(res11) # 6

# 12.判断是否有数据 exists()
# res12 = models.Books.objects.filter(pk=999).exists()
# print(res12) # False

# 13.update()
# 14.delete()

神奇的双下划线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
# 查询价格大于200的书籍
# res = models.Books.objects.filter(price__gt=200)
# print(res)
# res1 = models.Books.objects.filter(price__lt=200)
# print(res1)
# res2 = models.Books.objects.filter(price__gte=456.23)
# print(res2)
# res3 = models.Books.objects.filter(price__lte=456.23)
# print(res3)

# 成员运算
# res4 = models.Books.objects.filter(price__in=(456.23,111))
# print(res4)
# 范围查询
# res5 = models.Books.objects.filter(price__range=(100,456.23))
# print(res5)
# 模糊查询
# 查询书籍名称中含有字母a的书
# res6 = models.Books.objects.filter(title__contains='a')
# print(res6) # 区分
# res7 = models.Books.objects.filter(title__icontains='a')
# print(res7) # 忽略

# 日期相关
# 查看出版月份是五月的书
# res8 = models.Books.objects.filter(publish_time__month=5)
# print(res8)
# print(res8.query)
# res9 = models.Books.objects.filter(publish_time__year=2021)
# print(res9)

外键字段增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 增
# models.Book.objects.create(title='三国演义',price=345.43,publish_id=1)
# models.Book.objects.create(title='红楼梦',price=678.31,publish_id=2)

# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='三国演义',price=345.43,publish=publish_obj)
# models.Book.objects.create(title='七龙珠',price=908.43,publish=publish_obj)

# 改
# models.Book.objects.filter(pk=2).update(publish_id=1)
# models.Book.objects.filter(pk=2).update(publish=publish_obj)

# 删 级联更新级联删除
# models.Publish.objects.filter(pk=1).delete()


# 多对多
# book_obj = models.Book.objects.filter(pk=3).first()
# 绑定关系
# book_obj.authors.add(1) # 去书与作者的关系表中绑定关系
# book_obj.authors.add(1,2) # 去书与作者的关系表中绑定关系
# book_obj.authors.add(author_obj1)
# book_obj.authors.add(author_obj1,author_obj2)

# 修改关系
# book_obj.authors.set([1,])
# book_obj.authors.set([1,2])
# book_obj.authors.set([author_obj,])
# book_obj.authors.set([author_obj1,author_obj2])

# 移除关系
# book_obj.authors.remove(1)
# book_obj.authors.remove(1,2)
# book_obj.authors.remove(author_obj,)
# book_obj.authors.remove(author_obj1,author_obj2)

# 清空关系
# book_obj.authors.clear()

重要概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 多表查询
"""
正向查询

反向查询

当前查询对象是否含有外键字段
如果有就是正向
没有无则是反向
口诀:
正向查询按外键字段
多对多需要额外再加一个.all()
一对多和一对一不需要加
反向查询按表名小写
一对多与多对多
_set.all()
一对一
不需要加
"""

多表查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#####################基于对象的跨表查询#####################
# 子查询:将一张表的查询结果当做另外一条SQL语句的条件(括号括起来)
# 1.查询书籍主键为4的出版社名称
# 先查询书籍对象
# book_obj = models.Book.objects.filter(pk=4).first()
# 外键字段在书这里 所以是正向查询
# res = book_obj.publish
# print(res)
# print(res.title)
# print(res.addr)

# 2.查询书籍主键为3的作者姓名
# 先查询书籍对象
# book_obj = models.Book.objects.filter(pk=3).first()
# 外键字段在书这里 所以是正向查询
# res = book_obj.authors
# print(res) # app01.Author.None
# res = book_obj.authors.all()
# print(res) # <QuerySet [<Author: 作者对象:oscar>, <Author: 作者对象:egon>]>


# 3.查询作者jason的地址
# 先查询jason数据对象
# author_obj = models.Author.objects.filter(name='jason').first()
# 外键字段在作者这里 所以是正向查询
# res = author_obj.author_detail
# print(res)
# print(res.addr)
# print(res.phone)


# 4.查询东方出版社出版的书籍
# 先查询出版社对象
# publish_obj = models.Publish.objects.filter(title='东方出版社').first()
# 外键字段在书那里自己没有 所以是反向
# res = publish_obj.book_set
# print(res) # app01.Book.None
# res = publish_obj.book_set.all()
# print(res)


# 5.查询jason写过的书籍
# 先查询jason数据对象
# author_obj = models.Author.objects.filter(name='jason').first()
# 外键字段在书那里自己没有 所以是反向
# res = author_obj.book_set
# print(res) # app01.Book.None
# res = author_obj.book_set
# print(res) # app01.Book.None
# res = author_obj.book_set.all()
# print(res) # app01.Book.None


# 6.查询电话是120的作者
# 先查询120数据对象
# author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
# 外键字段在作者那里本身没有 所以是反向
# res = author_detail_obj.author
# print(res)
# print(res.name)
# print(res.age)



########################基于双下滑线的跨表查询
# 1.查询书籍主键为4的出版社名称
# res = models.Book.objects.filter(pk=4).values('publish__title','publish__addr','title')
# print(res)

# 2.查询书籍主键为3的作者姓名
# res = models.Book.objects.filter(pk=3).values('authors__name')
# print(res)

# 3.查询作者jason的地址
# res = models.Author.objects.filter(name='jason').values('author_detail__addr','name','age')
# print(res)

# 4.查询北方出版社出版的书籍名称
# res = models.Publish.objects.filter(title='北方出版社').values('book__title')
# print(res)

# 5.查询jason写过的书籍
# res = models.Author.objects.filter(name='jason').values('book__title','name','age')
# print(res)

# 6.查询电话是120的作者
# res = models.AuthorDetail.objects.filter(phone=120).values('author__name','author__age','addr')
# print(res)



############进阶操作#############
# 1.查询书籍主键为4的出版社名称
# res = models.Book.objects.filter(pk=4).values('publish__title','publish__addr','title')
# print(res)
# 反向查询高阶部分
# res = models.Publish.objects.filter(book__pk=4)
# print(res)

# 2.查询书籍主键为3的作者姓名
# res = models.Book.objects.filter(pk=3).values('authors__name')
# print(res)
# 反向查询高阶部分
# res = models.Author.objects.filter(book__pk=3)
# print(res)

# 3.查询作者jason的地址
# res = models.Author.objects.filter(name='jason').values('author_detail__addr','name','age')
# print(res)
# 反向查询高阶部分
# res = models.AuthorDetail.objects.filter(author__name='jason')
# print(res)


# 查询书籍主键为3的作者的电话号码
# res = models.Book.objects.filter(pk=3).values('authors__author_detail__phone')
# print(res)

# res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone')
# print(res)

# res = models.Author.objects.filter(book__pk=3).values('author_detail__phone')
# print(res)

F查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
   # F查询
from django.db.models import F
# 1.查询库存数大于卖出数的书籍
# res = models.Book.objects.filter(kucun__gt=F('maichu'))
# print(res)
# 2.将所有的书籍价格上涨100块
# res = models.Book.objects.update(price=F('price') + 100)
# print(res)
# 3.将所有的书籍名称加上"爆款"后缀
'''针对字符串不能直接拼接 需要额外导入模块操作'''
# models.Book.objects.update(title=F('title') + '爆款')
# from django.db.models.functions import Concat
# from django.db.models import Value
# ret3 = models.Book.objects.update(title=Concat(F('title'), Value('爆款')))

Q查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   # 1.查询书名是三国演义爆款或者库存是100的书籍
'''filter()括号内可以写多个参数 逗号隔开 默认只支持and连接'''
from django.db.models import Q
# res = models.Book.objects.filter(title='三国演义爆款',kucun=100)
# print(res)
# res1 = models.Book.objects.filter(Q(title='三国演义爆款'),Q(kucun=100)) # and
# res1 = models.Book.objects.filter(Q(title='三国演义爆款')|Q(kucun=100)) # or
# res1 = models.Book.objects.filter(~Q(title='三国演义爆款')|Q(kucun=100)) # not
# print(res1.query)
'''Q进阶用法'''
# condition = input('请输入你需要按照什么字段查询数据>>>:')
# data = input('请输入你需要查询的数据名称>>>:')
# q = Q() # 生成一个Q对象
# q.children.append((condition,data))
# res = models.Book.objects.filter(q)
# print(res)
q = Q()
q.connector = 'or' # 可以修改连接条件
q.children.append(('title__contains','三'))
q.children.append(('price__gt',200)) # 可以添加多个条件 并且也是and关系
res = models.Book.objects.filter(q)
print(res)
print(res.query)

事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"""
1.事务四大特性 ACID
原子性
一致性
独立性
持久性
2.数据库设计三大范式
课下百度搜索自己概括

MySQL
start transcation
commit
rollback
"""
from django.db import transaction
try:
with transaction.atomic():
# 创建一条订单数据
models.Order.objects.create(num="110110111", product_id=1, count=1)
# 能执行成功
models.Product.objects.filter(id=1).update(kucun=F("kucun") - 1, maichu=F("maichu") + 1)
except Exception as e:
print(e)

执行原生SQL语句

1
2
3
4
res = models.Book.objects.raw('select * from app01_book')
for i in res:
print(i)

模型层字段及参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
models.AutoField(primary_key=True)
models.CharField(max_length=32) # varchar(32)
models.IntergeField() # int()
models.DateField() # date
models.DateTimeField() # datetime
auto_now
auto_now_add
models.DecimalField() # float()
models.BooleanField()
给这个字段传布尔值会自动转换成数字01
一般用在状态二选一
TextField()
存储大段文本(bbs项目会使用)
EmailField()
存储邮箱格式数据
FileField()
存储数据路径(bbs项目会使用)

"""自定义字段"""
from django.db.models import Field


class MyCharField(Field):
def __init__(self,max_length,*args,**kwargs):
self.max_length = max_length
super().__init__(max_length=max_length,*args,**kwargs)

def db_type(self, connection):
return 'char(%s)'%self.max_length

常见参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
max_length
varbose_name
default
null
auto_now
auto_now_add
to
unique
db_index
choices

# choices参数
创建用户表
性别
两到三种状态
学历
也是有限个
在职状态
也是有限个
婚姻
也是有限个
...
"""针对某个字段可以列举完全的情况 一般都是使用choices参数"""
class Server(models.Model):
host = models.CharField(max_length=32)

status_choices = (
(1,'在线'),
(2,'待上线'),
(3,'宕机'),
(4,'待上架')
)
status = models.IntegerField(choices=status_choices)

desc_choices = (
('哈哈','哈哈哈哈哈哈'),
('呵呵','呵呵呵呵呵呵'),
('嘿嘿','嘿嘿嘿嘿嘿嘿'),
('嘻嘻','嘻嘻嘻嘻嘻嘻'),
)
desc = models.CharField(max_length=32,choices=desc_choices)

# 获取对应关系
.get_字段名_display()

ORM查询优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 惰性查询
用不到的数据即使写了orm语句也不会执行
1.only与defer
2.select_related与prefech_related


# 1.only与defer

# res = models.Book.objects.values('title') # 列表套字典

# res1 = models.Book.objects.only('title') # 列表套对象
# print(res1)
# for i in res1:
# # print(i.title)
# print(i.price)
"""
only括号内写什么字段
生成的对象就含有对应的属性 在查找该属性的时候不再走数据库查询
但是一旦查找括号内没有的字段属性 则每次都会走数据库查询

"""
# res1 = models.Book.objects.defer('title')
# # print(res1) # 列表套对象
# for i in res1:
# # print(i.title)
# print(i.title)
"""
defer与only刚好相反
生成的对象就不含有对应的属性 在查找该属性的时候需要每次走数据库查询
但是一旦查找括号内没有的字段属性 则不需要走数据库查询
"""
# res = models.Book.objects.filter(pk=3).first()
# print(res.publish.title)


# res = models.Book.objects.select_related('publish')
# for i in res:
# print(i.publish.title)
"""
select_related相当于连表操作
先将models后面的表和括号内外键字段关联的表连接起来
之后一次性把所有的数据封装到数据对象中
"""
res = models.Book.objects.prefetch_related('publish')
for i in res:
print(i.publish.title)
"""
prefetch_related相当于子查询
先查询models后面的表的所有的数据
然后将括号内关联的表的数据全部查询出来
之后整合到一起
"""

常用及非常用字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
AutoField(Field)
- int自增列,必须填入参数 primary_key=True

BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True

注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models

class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)

class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)

SmallIntegerField(IntegerField):
- 小整数 -3276832767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 032767
IntegerField(Field)
- 整数列(有符号的) -21474836482147483647

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 02147483647

BigIntegerField(IntegerField):
- 长整型(有符号的) -92233720368547758089223372036854775807

BooleanField(Field)
- 布尔值类型

NullBooleanField(Field):
- 可以为空的布尔值

CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度

TextField(Field)
- 文本类型

EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制

IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL

SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字

UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹

FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]

DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

FloatField(Field)
- 浮点型

DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度

BinaryField(Field)
- 二进制类型

对应关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
对应关系:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',

ORM字段参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#### null

用于表示某个字段可以为空。

#### **unique**

如果设置为unique=True 则该字段在此表中必须是唯一的 。

#### **db_index**

如果db_index=True 则代表着为此字段设置索引。

#### **default**

为该字段设置默认值。

### DateField和DateTimeField

#### auto_now_add

配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。

#### auto_now

配置上auto_now=True,每次更新数据记录的时候会更新该字段。



null 数据库中字段是否可以为空
db_column 数据库中字段的列名
db_tablespace
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引

verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}

validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)

关系字段

ForeignKey

外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 ‘一对多’中’多’的一方。

ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

to

设置要关联的表

to_field

设置要关联的表的字段

反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’。

例如:

1
2
3
4
5
6
class Classes(models.Model):
name = models.CharField(max_length=32)

class Student(models.Model):
name = models.CharField(max_length=32)
theclass = models.ForeignKey(to="Classes")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

1
models.Classes.objects.first().student_set.all()

当我们在ForeignKey字段中添加了参数 related_name 后,

1
2
3
class Student(models.Model):
name = models.CharField(max_length=32)
theclass = models.ForeignKey(to="Classes", related_name="students")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

1
models.Classes.objects.first().students.all()

反向查询操作时,使用的连接前缀,用于替换表名。

on_delete

  当删除关联表中的数据时,当前表与其关联的行的行为。

  models.CASCADE
  删除关联数据,与之关联也删除

  models.DO_NOTHING
  删除关联数据,引发错误IntegrityError

  models.PROTECT
  删除关联数据,引发错误ProtectedError

  models.SET_NULL
  删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)

  models.SET_DEFAULT
  删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

  models.SET

  删除关联数据,
  a. 与之关联的值设置为指定值,设置:models.SET(值)
  b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

1
2
3
4
5
6
7
8
9
def func():
return 10

class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func)
)

db_constraint

是否在数据库中创建外键约束,默认为True。

OneToOneField

一对一字段。

通常一对一字段用来扩展已有字段。

一对一的关联关系多用在当一张表的不同字段查询频次差距过大的情况下,将本可以存储在一张表的字段拆开放置在两张表中,然后将两张表建立一对一的关联关系。

1
2
3
4
5
6
7
8
class Author(models.Model):
name = models.CharField(max_length=32)
info = models.OneToOneField(to='AuthorInfo')


class AuthorInfo(models.Model):
phone = models.CharField(max_length=11)
email = models.EmailField()

to

设置要关联的表。

to_field

设置要关联的字段。

on_delete

同ForeignKey字段。

ManyToManyField

用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系

to

设置要关联的表

同ForeignKey字段。

同ForeignKey字段。

symmetrical

仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。

举个例子:

1
2
3
class Person(models.Model):
name = models.CharField(max_length=16)
friends = models.ManyToManyField("self")

此时,person对象就没有person_set属性。

1
2
3
class Person(models.Model):
name = models.CharField(max_length=16)
friends = models.ManyToManyField("self", symmetrical=False)

此时,person对象现在就可以使用person_set属性进行反向查询。

through

在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。

但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过through来指定第三张表的表名。

through_fields

设置关联的字段。

db_table

默认创建第三张表时,数据库中表的名称。