Django基础之模型层ORM(后篇)
模型层中的常见字段和参数
常见字段
AutoField()
- int自增列,必须填入参数 primary_key=True
IntegerField(Field)
- 整数列(有符号的),范围在 -2147483648 to 2147483647。
CharField()
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
- 参数:
auto_now=True
auto_now_add=True
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
# BooleanField(Field)
- 布尔值类型
- 在代码里面就是要True/False---------->在数据库中存的是0/1
# TextField(Field)
- 文本类型------------>可以存大段的文本------------->当字符串比较少的时候,一般用varchar(512)
---------->text----->存一篇文章
# FileField(Field) ------------> 可以上传文件
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
ImageField(FileField)
- 字符串,路径保存在数据库,图片上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
file = models.FileField(upload_to='文件上传的位置') # 什么类型都能上传
image = models.ImageField(upload_to='图片') # 只能上传图片
# FloatField(Field)
- 浮点型
# DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
ORM字段和mysql里字段的对应关系。
ORM | MYSQL |
---|---|
AutoField() | int auto_increment |
CharField() | 必须提供max_length参数,对应的数据库中是varchar类型 |
IntergerField() | int |
DecimalField() | decimal |
DateField() | date |
DateTimeField() | datetime |
BigIntergerField() | bigint |
BooleanField() | 传布尔值 存0和1 |
TextField() | 存储大段文本 |
FileField() | 传文件自动保存到指定位置并存文件路径 |
EmailField() | 本质还是varchar类型 |
常见参数
# null
用于表示某个字段可以为空。
# unique
如果设置为unique=True 则该字段在此表中必须是唯一的 。
# db_index
如果db_index=True 则代表着为此字段设置索引。
# default
为该字段设置默认值。
# auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
# auto_now
配置上auto_now=True,每次更新数据记录的时候会更新该字段。
参数 | 说明 |
---|---|
primary_key | 主键 |
max_length | 最大字符长度 |
verbose_name | 对应的名字 |
null | 是否可以为空 |
default | 默认值 |
max_digits | 数字允许的最大位数 |
decimal_places | 小数的最大位数 |
unique | 字段的值唯一 |
db_index | 是否为字段设置索引 |
auto_now | 更新修改数据时间 |
auto_now_add | 数据添加的时间 |
to | 设置关联的表 |
to_field | 设置关联的字段 |
db_constraint | 是否创建外键约束,默认True |
自定义字段(了解)
自定义char类型字段:
class FixedCharField(models.Field):
"""
自定义的char类型的字段类,要继承models.Field类
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为max_length指定的值
"""
return 'char(%s)' % self.max_length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
# 使用自定义的char类型的字段
cname = FixedCharField(max_length=25)
choices参数
当字段的可能性能够被列举完的时候,我们一般不存中文字符,男 女 未知,(因为中文字符占用资源多,读取慢)。一般使用choices参数存储这样的数据。
举例:
- 性别:男 女 保密
- 学历:小学 初中 高中 大学 硕士 博士 ...
- 来源:广告 QQ wechat 转介绍 自己过来的...
举例:存储性别字段
方式一:使用之前的方法,直接存储数字,后端来进行判断
gender = models.IntegerField() # 1, 2, 3
内部保存1,2,3。处理数据:从数据库中读取原始数据,得到的是整型,然后在python中做判断。如果gender等于1,给男。等于2,给女。
choices存值
方式二:使用choices参数
# 左边是变量名,起什么名字都可以。
gender_choices = ( # 括号可以是小括号,也可以是中括号。
(1, '男'), # 内部一定是元组,
(2, '女'),
(3, '未知'),
)
gender = models.IntegerField(choices=gender_choices)
"""
使用choices参数注意点:
1.字段数据类型:(1, '男'),元组中的第一个参数是什么类型,就选择对应的数据类型。因为数据库中存储的就是第一个参数的字段
2.存储的范围:是由你选择的字段数据类型决定的。
"""
第一个参数也可以写字母,eg:存储分数
score_choices = (
('A', '优秀'),
('B', '良好'),
('C', '及格'),
('D', '不及格'),
)
score = models.CharField(max_length=64, choices=score_choices)
取值
- 保存数据时,超出范围,可以存,存的数据是多少,数据库中就显示多少。
- 取值时,使用:对象.get_字段名_display(),就能取出数字被字段_choices映射的具体文本。
- 没有映射对象,可以保存,但是会原样返回。
多对多关系的三种创建方式
以图书表和作者表的多对多关系,来创建第三张表。
全自动的
- 虚拟字段,ManyToManyField字段
class Book(models.Model):
title = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=64)
优点:可以正反向查询,可以使用4个方法,add,set,remove,clear
缺点:不能在第三张表中增加其他字段,扩展性极差(公司中不要使用这种方式创建第三张表)
纯手动
- 建Book2Author表
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=64)
# 自己创建的第三张表
class Book2Author(models.Model):
# 外键关系字段
# 字段名中的_id,django会自动加上,不需要我们来写
book = models.ForeignKey(to='Book') # 关联图书表
author = models.ForeignKey(to='Author') # 关联作者表
# 其他字段
bind_time = models.DateTimeField(auto_now_add=True)
优点:扩展性很高。
缺点:需要自己操作第三张表中的数据,不支持正反向查询,不支持四种方法:add,set,remove,clear
纯手动创建的表,就需要自己手动去插入数据,更改数据,删除数据了:
models.Book2Author.objects.create(book_id=1, author_id=1)
半自动化
- 建Book2Author表
- 虚拟字段,ManyToManyField字段
class Book(models.Model):
title = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author',
through='Book2Author',
through_fields=('book', 'author') # 在Book表中写虚拟字段,book放在前面
)
"""
注意:
1. 还是需要创建一个虚拟字段authors----->models.ManyToManyField
2. through:指定第三张表的表名
3. through_fields:指定第三张表里面哪两个字段是关系字段
4. through_fields=('book', 'author')里面的两个字段是有顺序要求的,在那张表中建虚拟字段,把那个字段放在前面。
5. 这种方式是可以支持正反向查询的,但是不能使用那4个方法了,add remove set clear
"""
class Author(models.Model):
name = models.CharField(max_length=64)
# 也可以在作者表中创建这个虚拟字段,但是建议在查询频率较高的表中创建该虚拟字段。
# books = models.ManyToManyField(to='Book',
# through='Book2Author',
# through_fields=('author', 'book')
# )
class Book2Author(models.Model):
book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
author = models.ForeignKey(to='Author', on_delete=models.CASCADE)
bind_time = models.DateTimeField(auto_now_add=True)
优点:支持正反向查询
缺点:不支持四种方法:add,set,remove,clear
批量插入数据
题目:往book表插入10000条数据
方式1:直接循环插入
test.py文件:
import os
# Create your tests here.
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day57.settings')
import django
django.setup()
from app01 import models
for i in range(10000):
models.Book.objects.create(username='%s' % i)
"""
循环一次插入一条,连接一次数据库。
"""
方式2:bulk_create批量添加
bulk_create:批量添加
bulk_update:批量更新
test.py文件:
import os
# Create your tests here.
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day57.settings')
import django
django.setup()
from app01 import models
book_list = []
for i in range(100000):
book_obj = models.Book(username='%s' % i) # 实例化一个对象
book_list.append(book_obj)
# book_list里面是有10000个对象,并没有牵扯到数据库
# bulk_create:批量添加
# bulk_create的底层:一次插入多条数据 insert into table (username) values(1,'kevin'),(2,'kevin'),(3,'kevin'),(4,'kevin'),(5,'kevin'),(6,'kevin')
models.Book.objects.bulk_create(book_list)
# 不管数据有多大,只要不去查库,效率都可以忽略。
'''以后再实际项目中,能够一次操作数据库完成的动作,就要尽量使用一次性的,'''
面试题:
select * from app01 limit 1,500 # 第一页
select * from app01 limit 501,1000 # 第二页
select * from app01 limit 1001,1500 # 第三页
# select * from app01 # 查最后一页相当于查全表
select * from app01 limit 99501,100000 # 最后一页
问题:第一页的SQL语句的执行和最后一页的SQL语句的执行有区别吗?
答案:有,第一页,是只查询前500条数据。最后一页是把所有的数据都查询到了,只是把前99501条数据丢掉了,这个的效率是非常慢的。