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)

取值

  1. 保存数据时,超出范围,可以存,存的数据是多少,数据库中就显示多少。
  2. 取值时,使用:对象.get_字段名_display(),就能取出数字被字段_choices映射的具体文本。
  3. 没有映射对象,可以保存,但是会原样返回。

多对多关系的三种创建方式

以图书表和作者表的多对多关系,来创建第三张表。

全自动的

  • 虚拟字段,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条数据丢掉了,这个的效率是非常慢的。

posted @ 2023-05-06 17:17  星空看海  阅读(20)  评论(0编辑  收藏  举报