【Django】ORM模型类对数据库的增删改查、QuerySet查询集
1.shell
在Django项目,我们在对数据库的CRUD一般都是在视图函数里完成的,但是由于开发过程中可能会有很多测试,每次都写和运行的确不方便,所以我们可以借助Django提供的shell操作
python manage.py shell
打开shell之后,它会自动根据我们之前的配置连接数据库,接下来我们可以把之前写好的模型类导入
form 子应用名.models import 模型类名
from books.models import BookInfo,HeroInfo
2.增加数据
增加数据有两种方法
2.1 save()
创建一个对象,设置好属性之后,调用save()方法进行提交
book = BookInfo()
book.btitle = '三国演义'
book.bpub_date = '1998-05-06'
book.bread = 20
book.bcomment = 50
book.save()
2.2 create()
模型类.objects.create()
若新增成功,返回该对象
book = BookInfo.objects.create(
btitle='红楼梦',
bpub_date='2020-08-28',
bread=100,
bcomment=50
)
3.删除数据
删除也有两种方法
方法一:
book= BookInfo.objects.get(id=5)
book.delete()
方法二:
BookInfo.objects.filter(id=5).delete()
4.修改数据
修改数据也有两种方法
方法一:
book = BookInfo.objects.get(btitle="天龙八部")
book.btitle= "天龙八部2"
book.save()
方法二:
effect_num = BookInfo.objects.filter(btitle="天龙八部").update(btitle="天龙八部2")
# effect_num是受影响行数,可用来判断是否修改成功
5.查询数据
5.1 基本查询
1.get(),查询单一结果,当get不到符合条件的结果时会报异常的
book = BookInfo.objects.get(id=5)
book.btitle
2.first(),返回第一个符合要求的数据,匹配不对则返回None
User.objects.filter(username=username).first()
3.last(),返回最后一条记录
User.objects.filter(username=username).last()
4.all(),查询全部结果
BookInfo.objects.all() 返回QuerySet,包含全部结果,若无数据则返回一个空的QuerySet
5.count(),查询数量
BookInfo.objects.count() # 返回总结果数
6.exists(),如果QuerySet包含数据,就返回True,否则返回False
BookInfo.objects.exists()
7.exclude(**kwargs),返回不符合条件的记录
BookInfo.objects.exclude(name="pan")
8.values(*field),返回一个可当做列表套字典的QuerySet对象
BookInfo.objects.filter(**kwargs).values(*fields)
9.only(*field),返回一个可当做列表套字典的QuerySet对象,only和values 唯一的不同是only还会获取相应的id
BookInfo.objects.filter(**kwargs).only(*fields)
9.values_list(*field),返回一个可当做列表套元组的QuerySet对象
BookInfo.objects.filter(**kwargs).values_list(*fields)
5.2 过滤查询
过滤查询,类似于SQL的where关键字,filter过滤出满足条件的全部结果,而exclude是排除满足条件的全部结果
用法:用两个下划线链接属性名和比较运算符
属性名__比较运算符 = 值
常用运算符如下
运算符 | 说明 |
---|---|
exact | 相等,例如: BookInfo.objects.filter(idexact=1) |
exclude | 不等于,例如: BookInfo.objects.exclude(id=3) |
gt 、gte、lt、lte | gt(greater then),大于 gte(greater then equal),大于等于 lt(less then),小于 lte(less then equal),小于等于 |
contains | 包含某个字符,例如: BookInfo.objects.filter(btitlecontains=‘传’) |
startswith | 以某字符开头,例如: BookInfo.objects.filter(btitlestartswith=‘天’) |
endswith | 以某字符结尾,例如: BookInfo.objects.filter(btitleendswith=‘部’) |
isnull | 是否为空,True为空,False为非空,例如: BookInfo.objects.filter(btitleisnull=False) |
in | 在某个范围内,例如: BookInfo.objects.filter(idin=[1, 3, 5]) |
year | 年,类似的还有month、day、week_day、hour、minute、second,例如: BookInfo.objects.filter(bpub_date__year=1980) |
5.3 F对象
使用F对象可以比较属性
from django.db.models import F
BookInfo.objects.filter(bread__gte=F('bcomment'))
BookInfo.objects.filter(bread__gt=F('bcomment')*2)
5.4 Q对象
使用Q对象可以在逻辑关系中使用,可以配合与(&)、或(|)、非(~)运算符使用
from django.db.models import Q
1.查询阅读量大于20或者id小于3的图书
BookInfo.objects.filter(Q(bread__gt=20) | Q(id__lt=3))
2.查询id不等于3的图书
Book.objects.filter(~Q(id=3))
3.查询file字段为空的图书
Book.objects.filter(Q(file='') | Q(file=None))
5.5 聚合函数
使用聚合函数需要配合aggregate()过滤器
from django.db.models import Sum,Count,Avg,Max,Min
1.统计个数
BookInfo.objects.aggregate(Count('btitle'))
2.统计平均阅读量和总阅读量
BookInfo.objects.aggregate(Avg('bread'),Sum('bread'))
3.统计阅读量的最大值和最小值
BookInfo.objects.aggregate(Max('bread'),Min('bread'))
4.子表查询案例
sql = """select sum(a.amount) from (select * from btc_deposit WHERE wd_history_id = 0 ORDER BY amount DESC LIMIT 100) as a; """
amount__sum = BtcDeposit.objects.filter(wd_history_id=0).order_by("-amount").values("amount")[:100].aggregate(coinname=Sum('amount'))
# 返回一个字典:{"coinname": 25.021}
5.6 排序
我们可以使用order_by对结果进行排序
BookInfo.objects.all().order_by('bread') # 升序
BookInfo.objects.all().order_by('-bread') # 降序
5.7 关联查询
一对多: 一本书对应多个人物
b = BookInfo.objects.get(id=1) # 获取一个书本对象
b.heroinfo_set.all() # 多对应的模型类名小写_set
多对一: 多个人物出现在同一本书里
h = HeroInfo.objects.get(id=1) # 获取某个人物
h.hbook # 对应的关系类属性名
h = HeroInfo.objects.get(id=1) # 获取某个人物
h.hbook_id # 关联类属性_id
5.8 分页
如果想分页,可以直接切片查询集列表
query = Node.objects.filter(**filter_dict)
count = query.count() # 总个数
node_list = query.order_by(*order_by_list).all()[offset: offset + limit]
如果使用Django自带的分页器,可以参考另一篇博客
【Django】paginator分页器的简单使用
6.查询结果集(QuerySet)
当查询返回的结果有多条记录时,就得到一个QuerySet,我们可以使用exists()判断是否有数据,若有则返回True,若没有则返回False。
QuerySet有两大特性,惰性执行和缓存
1.惰性执行是指当语句输入之后并不会马上执行,而是直到调用数据的时候才会真的连接数据库进行操作。
2.缓存,就是当查询一次之后它会保留结果,而不是马上销毁,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数
序列化结果集,转成字典
from django.core import serializers
node_list = Node.objects.filter(**filter_dict).order_by(*order_by_list).all()
print("node_list:", node_list)
json_data = json.loads(serializers.serialize("json", node_list)) # 转成dict
print("json_data:", json_data)
上面通过serializers.serialize()方法转换出来的JSON会有一些其他信息,Django还提供了一个model_to_dict()方法进行转换
from django.forms import model_to_dict
node_list = Node.objects.filter(**filter_dict).order_by(*order_by_list).all()
node_list = [model_to_dict(m) for m in node_list]
上面这个方法可能会不是很好,有些字段可能会不能正常序列化,也可以自己写一个方法construction_dict(),该方法同样适用于Flask
def construction_dict(obj, model, field_name_list: list = None) -> dict:
d = dict()
# for c in field_name_list or model.__table__.columns: # flask
for c in field_name_list or model._meta.fields: # Django
attr_name = c if isinstance(c, str) else c.name
value = getattr(obj, attr_name)
if isinstance(value, datetime):
value = get_date_time_str(value)
if isinstance(value, Decimal):
value = str(value)
d[attr_name] = value
return d
def get_date_time_str(dt):
return dt.strftime("%Y-%m-%d %H:%M:%S") if dt and isinstance(dt, datetime) else None
还没有评论,来说两句吧...