Django提供了一套非常方便的类似SqlAlchemy ORM的通过对象调用的方式操作数据库表的ORM框架。
Django ORM
操作主要分为以下几类:
- 增:向表内插入一条数据
- 删:删除表内数据(物理删除)
- 改:update操作更新某条数据
- 查:基本的表查询(包括多表、跨表、子查询、联表查询)
其中比较复杂的是表查询。下面分类讲解这几种操作方式。
1 增 – 向表内插入一条数据
关于新增记录的操作这里分为两种方式:
- 第一种方式,通过模型对象的
save()
方法:
userObj=User()
userObj.username= request.data.get('username')
# userObj.password= make_password(request.POST.get('password'),None,'pbkdf2_sha256') # 创建django密码,第三个参数为加密算法
userObj.set_password(request.data.get('password')) # 创建django密码,第三个参数为加密算法
userObj.name= request.data.get('name')
userObj.phone= request.data.get('phone')
userObj.email= request.data.get('email')
userObj.create_name= request.data.get('create_name')
userObj.update_name= request.data.get('update_name')
userObj.is_superuser= 0
print(userObj.username)
print('username %s' % (userObj.username))
print('password %s' % (userObj.password))
userObj.save()
这种方式通过线创建一个模型对象,赋值,最后调用模型的 .save()
方法的方式向数据库插入一条数据。
- 第二种方式,通过objects.create的方式直接新增,类似一种缩略的方式,比较简单
res = models.User.objects.create(username='admin',make_password='123456',register_time=datetime.datetime.now())
print(res)
2 删 – 删除表内数据(物理删除)
django删除表数据是通过.delete()
方法,举例:
如果我们只删除 user表 主键为1的记录:
ret = models.User.objects.get(pk=1).delete()
上述是只删一条记录,删除多条记录类似:ret = models.User.objects.filter(pk__gt=1).delete()
这样我们可以批量删除user表中主键值大于1的其他所有记录。
需要提醒的是,这种方式属于物理删除,删除后不可恢复,如需逻辑删除,参考下面 update
的方式。
3 改 – update操作更新某条数据
django ORM 的改操作,这里分为三种方式。我们先按单记录的更新讲解,批量更新类似:
- 第一种,指定更新字段更新:
ret = models.User.objects.get(pk=1).update(username='admin',password='123456')
- 第二种,通过 Json 更新:
object = {'username':'admin','password':'123456'}
ret = models.User.objects.get(pk=1).update(**object)
- 第三种,类似增操作,直接通过
.save()
方法更新整条记录
userObj=User()
userObj.id= request.data.get('id')
userObj.username= request.data.get('username')
# userObj.password= make_password(request.POST.get('password'),None,'pbkdf2_sha256') # 创建django密码,第三个参数为加密算法
userObj.set_password(request.data.get('password')) # 创建django密码,第三个参数为加密算法
userObj.name= request.data.get('name')
userObj.phone= request.data.get('phone')
userObj.email= request.data.get('email')
userObj.create_name= request.data.get('create_name')
userObj.update_name= request.data.get('update_name')
userObj.is_superuser= 0
print(userObj.username)
print('username %s' % (userObj.username))
print('password %s' % (userObj.password))
userObj.save()
这种方式不太建议用,需要注意数据的完整性。
4 查 – 基本的表查询(包括多表、跨表、子查询、联表查询)
4.1 基本查询
需要了解如下方法的使用:
all()
查询所有数据filter()
带有过滤条件的查询where
get()
获取单条,查询不到会报错first()
取queryset
里第一条记录last()
取queryset
里最后一条记录values()
指定要获取的字段
models.User.objects.filter(pk=1).values('username','phone')
# 返回 <QuerySet [{'username': 'admin', 'phone': '176****'}]>
values_list()
列表套元祖
models.User.objects.filter(pk=1).values_list('username','phone')
# 返回 <QuerySet [('admin','176***')]>
distinct()
去重
ret = models.User.objects.filter(pk=1).distinct()
需要注意,这里去重是针对整条数据的去重,主键不一样也不会去重
order_by()
排序
ret = models.User.objects.order_by('username')# 默认升序
ret = models.User.objects.order_by('-username')# 降序
reverse()
反转,前提已排序
ret = models.User.objects.order_by('username').reverse()# 默认升序
ret = models.User.objects.order_by('-username').reverse()# 降序
count()
当前查询条件的记录数
ret = models.User.objects.filter(pk=1).count()
exclude()
排除 ,相当于查询条件不等于
ret = models.User.objects.exclude(pk=1)
exists()
记录是否存在,不太实用,不过多讲
4.2 双下划线查询条件
django不支持 类似:>=,<=等查询判断方式,但提供了一套很好用的方法:
-
__gt
<=> 大于:
ret = models.User.objects.filter(id__gt=1)#查询id>1的记录
-
__lt
<=> 小于:ret = models.User.objects.filter(id__lt=1)#查询id<1的记录
-
__gte
<=> 大于等于:ret = models.User.objects.filter(id__gte=1)#查询id>=1的记录
-
__lte
<=> 小于等于:ret = models.User.objects.filter(id__lte=1)#查询id<=1的记录
-
__in
<=> 条件是否归属所给的选择:ret = models.User.objects.filter(id__in=[1,2])#查询id=1或id=2的记录
-
__range
<=> 范围:ret = models.User.objects.filter(id__range=[1,3])#查询1<=id<=3的记录
-
__contains
<=> 模糊查询 ,区分大小写:ret = models.User.objects.filter(username__contains='a')#查询 username like '%a%'的记录
-
__icontains
<=> 模糊查询 ,不区分大小写:ret = models.User.objects.filter(username__icontains='a')#查询 username like '%a%'的记录
-
__startswith
<=> 模糊查询 ,指定内容开始:ret = models.User.objects.filter(username__icontains='a')#查询 username like 'a%'的记录
-
__endswith
<=> 模糊查询 ,指定内容结束:ret = models.User.objects.filter(username__icontains='a')#查询 username like '%a'的记录
注意:__contains
、__icontains
、__startswith
、__endswith
这些模糊查询性能很低,生产环境不建议使用。
4.3 逻辑查询:or、and、not
涉及概念:Django的Q对象
4.3.1 Q对象
Q对象实例化后能够增加各个条件之间的关系,而且这种写法用在你不知道用户到底传入了多少个参数的时候很方便。
- 比如默认情况下
filter()
里面每个字段的连接都是&
,我们使用Q对象通常都是让它变成|
,来进行查询 。
from django.db.models import Qquery = Q()
q1 = Q()
q1.connector = "AND" # 连接的条件是AND 代表就是&
q1.children.append(("email", "280773872@qq.com")) # email代表的是数据库的字段
q1.children.append(("password", "666"))# 等同于:email="280773872@qq.com" & password="666"
q2 = Q()
q2.connector = "AND" # 同样q2对象连接条件也是AND
q2.children.append(("username", "fe_cow")) # 同样数据库里username字段
q2.children.append(("password", "fe_cow666"))# 等同于:username="fe_cow" & password="fe_cow666"
query.add(q1, "OR")
query.add(q2, "OR")# query目前里面的符合条件结果就是: (email="280773872@qq.com" & password="666") | (username="fe_cow" & password="fe_cow666")
userinfo_obj = models.UserInfo.objects.filter(query).first()
filter()
过滤器的方法中关键字参数查询,会合并为And()
,需要进行or
查询,使用Q()
对象,Q对象django.db.models.Q
用于封装一组关键字参数,这些关键字参数与比较运算符
中的相同。
- Q对象可以使用
&(and)、|(or)
操作符组合起来,当操作符应用在两个Q对象时,会产生一个新的Q对象。
list.filter(pk__lt=6).filter(bcomment__gt=10)
list.filter(Q(pk__lt=6) | Q(bcomment__gt=10))
-
使用
~
操作符在Q对象前表示取反:list.filter(~Q(pk__lt=6))
-
可以使用
&|~
结合括号进行分组,构造出复杂的Q对象
4.3.2 or、and、not
import os
import djangoos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False)from employee.models import Employees # 这一行必须在`os.environ.setdefault`之后,先把配置、环境变量准备好后才能import
from django.db.models import Q
# emps = Employees.objects.all() # 懒查询,只有后面对查询结构有引用时,才会驱动真正的查询
# print(emps) # 查询集mgr = Employees.objects
# AND查询: 五种方式
x = mgr.filter(pk__gt=10005, pk__lt=10010)
print(x)
y = mgr.filter(pk__gt=10005).filter(pk__lt=10010)
print(y)
z = mgr.filter(pk__gt=10005) & mgr.filter(pk__lt=10010)
print(z)
# Django的Q对象
xx = mgr.filter(Q(pk__gt=10005) & Q(pk__lt=10010))
yy = mgr.filter(Q(pk__gt=10005), Q(pk__lt=10010))# OR查询: 三种方式
x = mgr.filter(pk__in=[10005, 10010])
print(x)
y = mgr.filter(pk=10005) | mgr.filter(pk=10010)
print(y)
z = mgr.filter(Q(pk=10005) | Q(pk=10010))# NOT查询:
x = mgr.exclude(pk=10005)
print(x)
y = mgr.filter(~(Q(pk__gt=10005) & Q(pk__lt=10010)))
print(y)
4.3.3 集合查询
# 聚合
from django.db.models import Max, Min, Count, Sum, Avg
x = mgr.filter(pk__gt=10008).count() # 将所有数据看做一行出结构
print(x) # 单值
# aggregate聚合函数:出统计函数的结果,返回字典,默认key命名为`字段名_聚合函数名`
y = mgr.filter(pk__gt=10008).aggregate(Count("pk"), Max("pk"), Min("pk"), sm_pk=Sum('pk'), avg_pk=Avg('pk')) # 可以给聚合查询结果起别名
print(y)
# 结果:{'sm_pk': 120174, 'avg_pk': 10014.5, 'pk__count': 12, 'pk__max': 10020, 'pk__min': 10009}
# annotate聚合函数:这个聚合函数会分组,没有指定分组使用pk分组,行行分组。返回结果集
z = mgr.filter(pk__gt=10013).annotate(Count("pk"), Max("pk"), Min("pk"), sm_pk=Sum('pk'), avg_pk=Avg('pk'))
print(z)
xx = mgr.filter(pk__gt=10013).values('gender').annotate(c=Count("pk")).values("c") # 第一个values控制分组,第二个values控制投影
print(xx)
4.4 多表查询
4.4.1 多对多查询
我们先定义两张表:User表(用户表),Artile表(文章表),一篇文章可以被多个用户关注,一个用户也可以关注多篇文章,二者是多对多的关系。
from django.db import models
import datetimeclass Artile(models.Model):"""title: 标题sub_title: 子标题content: 内容"""def __str__(self):return self.titletitle = models.CharField(max_length=250,default='',verbose_name='标题')sub_title = models.CharField(max_length=250,default='',verbose_name='子标题')content = models.CharField(max_length=2000,default='',blank=True,verbose_name='内容')# 与User表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表users = models.ManyToManyField(to='User', )create_time = models.DateTimeField(default=datetime.datetime.now(),verbose_name='创建时间')create_name = models.CharField(max_length=20,verbose_name='创建人')update_time = models.DateTimeField(default=datetime.datetime.now(),blank=True,verbose_name='更新时间')update_name = models.CharField(max_length=20,verbose_name='更新人',blank=True,)is_delete = models.IntegerField(default=0,verbose_name='删除状态',blank=True,) # 逻辑删除 0 正常 1:删除class Meta:verbose_name = "文章"verbose_name_plural = verbose_nameapp_label = 'webApi'
from django.db import models
import datetime
#引入系统用户的分类
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.hashers import make_password #密码加密#userProfile继承AbstractUser分类,进行拓展
class User(AbstractUser):"""name: 昵称account: 用户名pwd: 密码phone:手机号email:邮箱avator:头像group_id:归属组"""def __str__(self):return self.accountname = models.CharField(max_length=20,default='',verbose_name='昵称')phone = models.CharField(max_length=20,default='',blank=True,verbose_name='手机号')email = models.CharField(max_length=20,default='',blank=True,verbose_name='邮箱')avator = models.CharField(max_length=200,default='',blank=True,verbose_name='头像')group_id = models.CharField(max_length=50,default='',blank=True,verbose_name='组')create_time = models.DateTimeField(default=datetime.datetime.now(),verbose_name='创建时间')create_name = models.CharField(max_length=20,verbose_name='创建人')update_time = models.DateTimeField(default=datetime.datetime.now(),blank=True,verbose_name='更新时间')update_name = models.CharField(max_length=20,verbose_name='更新人',blank=True,)is_delete = models.IntegerField(default=0,verbose_name='删除状态',blank=True,) # 逻辑删除 0 正常 1:删除# blank=True, 可选字段class Meta:verbose_name = "用户"verbose_name_plural = verbose_namedef __str__(self):return self.username# 明文密码转加密def set_password(self, password):print('set_password %s' % (password))self.password = make_password(password,'jxy','pbkdf2_sha256')# 验证密码是否匹配def check_password(self, password):print('password: %s' % (password))print('check_password: %s' % (make_password(password,'jxy','pbkdf2_sha256')))print('self.password: %s' % (self.password))return self.password == make_password(password,'jxy','pbkdf2_sha256')
注意我们在Artile表中定义的users = models.ManyToManyField(to='User')
,通过这种定义方式,我们在 Artile表与User表之间创建了一个针对这两张表的关系表。
接下来我们向这张关系表中添加几条关系。比如,我们将 Artile表主键为1的一条记录,添加User表 主键为1,2两条关系。
user1 = models.User.object.filter(pk=1).first()
user2 = models.User.object.filter(pk=2).first()artile1 = models.Artile.object.filter(pk=1).first()
artile1.users.add(user1,user2)# 方法二
userSet = models.User.object.filter(pk__in=[1,2]).all()
artile1.users.add(*userSet)
这样便在关系表中创建了 Artile表主键为1的记录 与 User表 主键为1,2的两条关系。
另外清除关系绑定用法类似,使用remove替代add:
artile1 = models.Artile.object.filter(pk=1).first()
userSet = models.User.object.filter(pk__in=[1,2]).all()
artile1.users.remove(*userSet) #解绑指定关系
artile1.users.clear() #清空所有关系
多对多查询:
- 正向查询,例如查询Artile表第一条记录有哪些用户关注:
artile1 = models.Artile.object.filter(pk=1).first()
print(artile1.users.all().values('username')) # 打印关注Artile表第一条记录的用户名称
- 逆向查询,例如查询User表第一条记录关注过哪些Artile:
user1 = models.User.object.filter(pk=1).first()
print(user1.artile__set.all().values('title')) # 打印User表第一条记录关注的文章名称
4.4.2 一对多查询
参考:
https://juejin.cn/post/6974298891353063431