ORM模型
一. 数据库
-
django配置MySQL
- 使用mysqlclient[版本mysqlclient 1.3.13以上]
- 安装前确认ubuntu是否已安装python3-dev 和 default-libmysqlclient-dev
- 使用命令检查是否安装sudo apt list --installed|grep -E 'libmysqlclient-dev|python3-dev’若无命令输出则需要安装
- 安装命令:
sudo apt-get install python3-dev default-libmysqlclient-dev
- 安装mysqlclient:
sudo pip install mysqlclient
- 如出现如下报错:unable to execute ‘x86_64-linux-gnu-gcc’: No such file or directory 则需在linux终端执行
sudo apt-get install gcc
- 使用pymysql
- 使用
pip install pymysql
安装pymysql
- 使用
- 对比:
- mysqlclient是C扩展类,安装麻烦,运行速度快;
- pymysql是纯python实现,安装简单,运行速度不及mysqlclient
- 使用mysqlclient[版本mysqlclient 1.3.13以上]
-
创建项目对应的数据库
-
进入mysql数据库执行:
- create database 数据库名 default charset utf8 #创建数据库设置默认编码格式为utf8
- 通常数据库名保持跟项目名一致
-
在settings.py文件中进行数据库的配置
-
修改DATABASES 配置项的内容,将sqlite3改为mysql
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', #指定数据库的存储引擎 'NAME': 'mysql_demo', #指定要连接的数据库的名称 'USER': 'root', #指定登陆到数据库的用户名 'PASSWORD': 'mysql', #数据库登录密码 'HOST': '127.0.0.1', #连接数据库的IP 'PORT': '3306', #连接数据库的端口 } }
-
-
ENGINE:常见的引擎还有:
‘django.db.backends.mysql’ ‘django.db.backends.sqllite3’ ‘django.db.backends.oracle’ ‘django.db.backends.postgresql’
-
二. 模型类
- 模型
- 定义:是一个python类,它是由django.db.models.Model派生出的子类(即它必须继承至django.db.models.Model)
- 一个模型类代表着数据库的一张数据表
- 模型类中的每一个类属性都代表着数据库中的一个字段
- 模型是数据库交互的接口,是表示和操作数据库的方法和方式
三. ORM框架
-
定义:ORM(object relational mapping) 对象关系映射,它是一种程序技术,允许使用类和对象对数据库进行操作,避免了通过sql语句操作数据库
-
作用:
- 建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库
- 根据设计的模型类来生成数据库中的表格
- 通过简单的配置就可进行数据库的切换(切换settings.py文件中配置的数据库名即可)
-
优点:
- 只需要面向对象编程,不需要面向数据库编写代码
- 对数据库的操作都转换成对类属性和方法的操作
- 不用编写各种数据库的sql语句
- 实现了数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异
- 不在关注用的数据库是mysql、oracle…等数据库的内部细节
- 通过简单的配置就可以轻松更换数据库,而不需要修改代码
-
缺点:
- 对于复杂业务,使用成本较高(对于查询很复杂的业务,需要学习如何使用ORM来实现)
- 根据对象的操作转换成sql语句,根据查询的结果转化成对象,在映射的过程中会有性能损失
-
ORM 映射图
-
模型示例:
-
在子应用中的模型类中添加模型类及字段
from django.db import models # Create your models here. class Book(models.Model): book_name = models.CharField(verbose_name='书名',max_length=50,default='') price = models.DecimalField(verbose_name='价格',max_digits=7,decimal_places=2)
-
数据库迁移
- 迁移是django用来同步对模型所做更改(添加字段,删除模型等)到同步到数据库的方式
- 生成迁移文件 - 执行python manage.py makemigrations 将应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中
- 执行迁移脚本程序 - python manage.py migrate 执行迁移程序实现迁移,将每个应用下的migrations目录中的中间文件同步到数据库
- 迁移生成的数据库表名为:应用名_模型类类名
- 迁移是django用来同步对模型所做更改(添加字段,删除模型等)到同步到数据库的方式
-
-
创建模型类流程总结
-
创建应用
-
在应用下的models.py文件中编写模型类
from django.db import models class ModelName(models.Model): FieldName = models.FieldType(field-options) """ FieldName:字段名,迁移后对应数据表中字段名 FieldType:字段类型 field-options:字段选项 """
-
迁移同步 makemigrations&migrate
注意: 任何关于表结构的修改,务必在对应模型类上进行修改; 向模型类中添加字段时需要设置默认值;
-
-
字段类型
字段类型 数据库类型 作用 参数 BooleanField() tinyint(1) 使用True或False来表示值 - CharField() varchar - max_length:字符最大长度(必填参数) DateField() date 表示日期 auto_now:每次保存对象时, 自动设置该字段为当前时间(True/False); auto_now_add:当对象第一次被创建时自动设置当前时间(True/False); default:设置当前默认时间(取值:字符串格式时间,如’2021-7-1’) * 以上三个参数只能多选一 DateTimeField() datetime(6) 表示日期和时间 参数通DateField FloatField() double 使用小数表示值 - DecimalField() decimal(x,y) 使用小数表示值 max_digits:位数总长度, 包括小数点后的位数, 该值必须大于等于decimal_places;decimal_places: 小数点后的数字长度(即小数位数) *以上两个参数必选 EmailField() varchar 表示邮箱 - IntegerField() int 表示整数 - ImageField() varchar(100) 在数据库中为了保存图片的路径 - TextField() longtext 表示不定长的字符数据 - 注:更多字段类型说明参考官方文档
-
字段选项
字段选项用于指定创建列的额外的信息;允许出现多个字段选项,多个选项之间用逗号隔开字段选项 说明 primary_key 如果设置为True,表示该列为主键,如果指定一个字段为主键,则此数据库不会创建id字段 blank 设置为True时,该字段可以为空(在管理后台中编辑数据的时候可以为空),设置为False时,该字段时必须填写的 null 设置为True时,表示该列值允许为空,默认为False,如果此项为False时建议加入default选项来设置默认值 default 设置所在列的默认值,如果字段null=false建议添加此项 db_index 设置为True时,表示为该列增加索引 unique 设置为True时,表示该字段在数据库中的值必须是唯一不能重复出现的 db_column 指定列的名称,如果不指定的话则采用类属性名作为列名 verbose_name 设置此字段在admin界面显示的名称,不设置则默认以类属性名显示 注:更多字段选项说明参考官方文档
-
模型类 - Meta类(控制表相关属性)
-
定义:使用内部Meta类来给模型赋予属性,Meta类下有很多内建的类属性,可对模型类做一些控制
-
常见Meta类的内建属性:
属性 作用 db_table=‘数据表名’ 修改该模型所用的数据表的名称,设置完成后需要立马更新同步数据库 verbose_name=‘单数名’ 给模型一个易于理解的名称(单数),用于显示在/admin管理界面中 verbose_name_plural=‘复数名’ 该对象复数形式的名称,用于显示在/admin管理界面中 -
更改当前模型类对应的表名
#file:models.py from django.db import models class Books(models.Model): class Meta: db_table = 'book' #改变当前模型类对应的表名为book
-
ORM 基本操作 包括数据库的增删改查(增加:Create、读取:Read、更新:Update、删除:Delete)
-
ORM CRUD核心 -> 模型类.管理器对象
-
管理器对象: 每个继承自models.Model的模型类,都会有一个objects对象被同样继承下来,这个对象就叫管理器对象
class MyModel(models.Model): ··· MyModel.objects.create(···) #objects就是管理器对象
-
创建数据 -> 创建数据中每一条记录就是创建一个数据对象
- 方案一:MyModel.objects.create(属性1=值1,属性2=值2)
- 成功:返回创建好的数据
- 失败:抛出异常
- 方案二:创建MyModel实例对象,并调用save()进行保存
- obj = MyModel()
- obj.属性1 = 值1
- obj.属性2 = 值2
- obj.save() #执行save()后数据才会提交到数据库中
- django shell :在django中提供了一个交互式的操作项目交django shell,它能够在交互模式用项目工程的代码执行相应的操作;利用django shell 可以代替编写view的代码来进行直接操作 注意:项目代码发生变化时,需要重新进入django shell; 进入方式: python manage.py shell
- 方案一:MyModel.objects.create(属性1=值1,属性2=值2)
-
查询数据 -> 数据库的查询也需要使用管理器对象进行(可用QuerySet对象.query显示ORM转换为SQL语句的查询方法)
-
通过MyModel.objects管理器方法调用查询方法
方法 用法 作用 返回值 all() MyModel.objects.all() 查询MyModel表中的所有数据,等同于select * from table QuerySet容器对象,内部存放MyModel实例, ]> values( ‘列1’, ‘列2’) MyModel.objects.values() 查询部分列的数据并返回,等同于select 列1,列2 from table QuerySet容器对象,内部存放字典, 每个字典代表一条数据;格式为{‘列1’:值1,‘列2’:值2} values_list( ‘列1’, ‘列2’) MyModel.objects.values_list() 返回元组形式的查询结果,等同于select 列1,列2 from xxx QuerySet容器对象,内部存放元组, 会将查询出来的数据封装到元组中,再封装到查询集合QuerySet中, 如果需要将查询结果取出,需要使用索引的方式取值 order_by( ‘列1’, ‘列2’) MyModel.objects.order_by() 与all()方法不同, 它会用SQL语句的ORDER BY子句对查询结果进行根据某个字段选择性的进行排序, 默认是按照升序排序,降序排序需要在列前面增加‘-’表示 QuerySet容器对象,内部存放MyModel实例, 将实例按指定字段进行排序(等同于MyModel.objects.all().order_by(‘列1’)) filter(条件) MyModel.objects.filter(属性1=值1,属性2=值2) 多个属性在一起时为“与”关系 返回包含此条件的全部的数据集 QuerySet容器对象,内部存放MyModel实例 exclude(条件) MyModel.objects.exclude(条件) 多个属性在一起时为“与”关系 返回不包含此条件的全部的数据集 QuerySet容器对象,内部存放MyModel实例 get(条件) MyModel.objects.get(条件) 返回满足条件的唯一一条数据,查询结果多余一条数据则抛出Model.MultipleObjectsReturned异常,查询结果如果没有数据则抛出Model.DoesNotExist异常 QuerySet容器对象,内部存放MyModel实例 -
查询谓词
- 定义:做更灵活的条件查询时需要使用查询谓词
- 说明:每一个查询谓词是一个独立的查询功能
- 语法:类属性__查询谓词
更多查询谓词参考官方文档查询谓词 说明 示例 __exact 等值匹配 Author.objects.filter(id__exact==1) 等同于select * from author where id = 1 __contains 包含指定值 Author.objects.filter(name__contains=‘w’) 等同于select * from author where name like ‘%w%’ __startwith 以xxx开始 Author.objects.filter(name__startwith=‘w’) 等同于select * from author where name like ‘w%’ __endwith 以xxx结束 Author.objects.filter(name__endwith=‘w’) 等同于select * from author where name like ‘%w’ __gt 大于指定值 Author.objects.filter(age__gt=50) 等同于select * from author where age > 50 __gte 大于等于指定值 Author.objects.filter(age__gte=50) 等同于select * from author where age >= 50 __lt 小于指定值 Author.objects.filter(age__lt=50) 等同于select * from author where age < 50 __lte 小于等于指定值 Author.objects.filter(age__lte=50) 等同于select * from author where age <= 50 __in 查找数据是否在指定范围内 Author.objects.filter(country__in=[‘中国’,‘日本’,‘韩国’]) 等同于select * from author where country in [‘中国’,‘日本’,‘韩国’] __range 查找数据是否在指定的区间范围内 Author.objects.filter(age__range=(30,50)) 等同于select * from author where author between 35 and 50
-
-
ORM 更新操作
-
更新单个数据 - > 修改单个实体的某些字段值的步骤
- 查 -> 通过get()得到要修改的实体对象
- 改 -> 通过对象.属性 的方式修改数据
- 保存 -> 通过对象.save()保存数据
-
批量更新数据 -> 直接调用QuerySet的update(属性=值)实现批量修改
#示例 #将id大于3的所有图书价格定位0元 books = Book.objects.filter(id__gt==3) books.update(price=0)
-
-
ORM 删除操作
-
单个数据删除 :
-
查 -> 查找查询结果对应的一个数据对象
-
删 -> 调用这个数据对象的delete()方法实现删除
try: auth = Author.objects.get(id=1) auth.delete() except: print("删除失败") ```
-
-
批量数据删除
-
查 -> 查找查询结果中满足条件的全部QuerySet查询集合对象
-
删 -> 调用查询集合对象的delete()方法实现删除
#删除年龄≥65的全部信息 auths = Author.objects.filter(age__gt=65) auths.delete()
-
-
伪删除
- 通常不会轻易在业务里把数据真正删掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active、is_delete),默认是True;执行删除时,将要删除数据的(is_active、is_delete)字段值设为False
- 注意:用伪删除时,确保显示数据的地方,均加了is_active/is_delete=True的过滤查询
-
-
F对象
-
定义:一个F对象代表数据库中某条记录的字段的信息
-
作用:
- 通常是对数据库中的字段值在不获取的情况下进行操作
- 用于类属性(字段)之间的比较
-
语法:
from django.db.models import F f('列名')
-
-
Q对象
-
作用:在条件中用来实现逻辑或 | 、逻辑非~、逻辑与&等操作
-
语法:
from django.db.models import Q Q(条件1) | Q(条件2) #条件1或者条件2成立 Q(条件1) & Q(条件2) #条件1和条件2同时成立 Q(条件1) &~ Q(条件2) #条件1成立且条件2不成立
F对象与Q对象举例见链接
-
四. F对象和Q对象
-
F对象(标记字段)
-
定义:一个F对象代表数据库中某条记录的字段的信息
-
作用:
-
通常时对数据库中的字段值不获取的情况下进行操作
-
用于类属性(字段)之间的比较
-
语法
from django.db.models import F f('列名')
-
-
示例1:
#更新Book实例中,将每本书的零售价上涨10元 -- F对象实现 Book.objects.all().update(market_price=F('market_price') + 10) # market_price += 10 #等同于sql语句 -> UPDATE 'bookstore_book' SET 'market_price' = ('bookstore_book'.'market_price' + 10)
#更新Book实例中,将每本书的零售价上涨10元 -- 常规操作实现 books = Book.objects.all() for book in books: book.market_price = book.market_price + 10 #先将每本书的售价查询出来,再加上10 book.save()
-
示例2:文章点赞
# 常规点赞操作 def add_like(request,topic_id): topic = Topic.objects.get(id = topic_id) #查询出点赞的文章 new_like = topic.like + 1 #取出当前文章的点赞数,并增加1 """等同于sql语句:update topic set like =1 where id = xxx""" topic.like = new_like #将增加后的点赞数复制到字段中 topic.save() # 保存
#使用F对象实现 def add_like(request,topic_id): topic = Topic.objects.get(id = topic_id) #查询出点赞的文章 topic.like = F('like') + 1 #等同于 topic.like += 1 """等同与mysql 语句: update topic set like = like +1 where id = xxx""" topic.save()
使用常规方法实现点赞:假设同时有一万条点赞数据进行并行处理,这一万条数据的topic.like查询到的like值都为0,执行new_like = topic.like + 1后like的值都为1,提交到数据库后like的值也是1;
使用F对象实现点赞操作:利用mysql的innodb引擎的行锁功能,在进行数据的写入更新时,别人是操作不了数据的,间接性的上了一把锁,防止数据库多事物并发的问题。(like = like +1都是在like的基础上like+=1,而不是set like = 1) -
示例3:对数据库中两个字段的值进行比较,列出哪些书的零售价高于定价
#使用F对象实现 from django.db.models import F from bookstore.models import Book books = Book.objects.filter(market_price__gt=F('price')) """等同于sql语句:SELECT * FROM 'bookstore_book' WHERE 'bookstore_book'.'market_price' > ('bookstore_book'.'price')""" for book in books: print(book.title,'定价:',book.price,'现价:',book.market_price)
-
-
Q对象(或与非)
-
作用:在条件中用来实现逻辑或 | 、逻辑非~、逻辑与&等操作
-
语法:
from django.db.models import Q Q(条件1) | Q(条件2) #条件1或者条件2成立 Q(条件1) & Q(条件2) #条件1和条件2同时成立 Q(条件1) &~ Q(条件2) #条件1成立且条件2不成立
-
示例1:
#过滤出定价低于20元或者清华大学出版社出版的全部书籍 Book.objects.filter(Q(price__lt=20) | Q(pub='清华大学出版社'))
-