ORM模型
一. 数据库二. 模型类三. ORM框架四. F对象和Q对象
一. 数据库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
- 使用pip install pymysql 安装pymysql
mysqlclient是C扩展类,安装麻烦,运行速度快;pymysql是纯python实现,安装简单,运行速度不及mysqlclient
创建项目对应的数据库
进入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目录中的中间文件同步到数据库
创建模型类流程总结
创建应用
在应用下的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 = 值1obj.属性2 = 值2obj.save() #执行save()后数据才会提交到数据库中 django shell :在django中提供了一个交互式的操作项目交django shell,它能够在交互模式用项目工程的代码执行相应的操作;利用django shell 可以代替编写view的代码来进行直接操作 注意:项目代码发生变化时,需要重新进入django shell; 进入方式: python manage.py shell
查询数据 -> 数据库的查询也需要使用管理器对象进行(可用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='清华大学出版社'))



