【Django】ORM模型类对数据库的增删改查、QuerySet查询集

ゝ一世哀愁。 2022-12-02 00:52 226阅读 0赞

1.shell

在Django项目,我们在对数据库的CRUD一般都是在视图函数里完成的,但是由于开发过程中可能会有很多测试,每次都写和运行的确不方便,所以我们可以借助Django提供的shell操作

  1. python manage.py shell

打开shell之后,它会自动根据我们之前的配置连接数据库,接下来我们可以把之前写好的模型类导入

  1. form 子应用名.models import 模型类名
  2. from books.models import BookInfo,HeroInfo

2.增加数据

增加数据有两种方法

2.1 save()

创建一个对象,设置好属性之后,调用save()方法进行提交

  1. book = BookInfo()
  2. book.btitle = '三国演义'
  3. book.bpub_date = '1998-05-06'
  4. book.bread = 20
  5. book.bcomment = 50
  6. book.save()
2.2 create()

模型类.objects.create()
若新增成功,返回该对象

  1. book = BookInfo.objects.create(
  2. btitle='红楼梦',
  3. bpub_date='2020-08-28',
  4. bread=100,
  5. bcomment=50
  6. )

3.删除数据

删除也有两种方法

  1. 方法一:
  2. book= BookInfo.objects.get(id=5)
  3. book.delete()
  4. 方法二:
  5. BookInfo.objects.filter(id=5).delete()

4.修改数据

修改数据也有两种方法

  1. 方法一:
  2. book = BookInfo.objects.get(btitle="天龙八部")
  3. book.btitle= "天龙八部2"
  4. book.save()
  5. 方法二:
  6. effect_num = BookInfo.objects.filter(btitle="天龙八部").update(btitle="天龙八部2")
  7. # effect_num是受影响行数,可用来判断是否修改成功

5.查询数据

5.1 基本查询
  1. 1.get(),查询单一结果,当get不到符合条件的结果时会报异常的
  2. book = BookInfo.objects.get(id=5)
  3. book.btitle
  4. 2.first(),返回第一个符合要求的数据,匹配不对则返回None
  5. User.objects.filter(username=username).first()
  6. 3.last(),返回最后一条记录
  7. User.objects.filter(username=username).last()
  8. 4.all(),查询全部结果
  9. BookInfo.objects.all() 返回QuerySet,包含全部结果,若无数据则返回一个空的QuerySet
  10. 5.count(),查询数量
  11. BookInfo.objects.count() # 返回总结果数
  12. 6.exists(),如果QuerySet包含数据,就返回True,否则返回False
  13. BookInfo.objects.exists()
  14. 7.exclude(**kwargs),返回不符合条件的记录
  15. BookInfo.objects.exclude(name="pan")
  16. 8.values(*field),返回一个可当做列表套字典的QuerySet对象
  17. BookInfo.objects.filter(**kwargs).values(*fields)
  18. 9.only(*field),返回一个可当做列表套字典的QuerySet对象,onlyvalues 唯一的不同是only还会获取相应的id
  19. BookInfo.objects.filter(**kwargs).only(*fields)
  20. 9.values_list(*field),返回一个可当做列表套元组的QuerySet对象
  21. BookInfo.objects.filter(**kwargs).values_list(*fields)
5.2 过滤查询

过滤查询,类似于SQL的where关键字,filter过滤出满足条件的全部结果,而exclude是排除满足条件的全部结果

  1. 用法:用两个下划线链接属性名和比较运算符
  2. 属性名__比较运算符 =

常用运算符如下














































运算符 说明
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对象可以比较属性

  1. from django.db.models import F
  2. BookInfo.objects.filter(bread__gte=F('bcomment'))
  3. BookInfo.objects.filter(bread__gt=F('bcomment')*2)
5.4 Q对象

使用Q对象可以在逻辑关系中使用,可以配合与(&)、或(|)、非(~)运算符使用

  1. from django.db.models import Q
  2. 1.查询阅读量大于20或者id小于3的图书
  3. BookInfo.objects.filter(Q(bread__gt=20) | Q(id__lt=3))
  4. 2.查询id不等于3的图书
  5. Book.objects.filter(~Q(id=3))
  6. 3.查询file字段为空的图书
  7. Book.objects.filter(Q(file='') | Q(file=None))
5.5 聚合函数

使用聚合函数需要配合aggregate()过滤器

  1. from django.db.models import Sum,Count,Avg,Max,Min
  2. 1.统计个数
  3. BookInfo.objects.aggregate(Count('btitle'))
  4. 2.统计平均阅读量和总阅读量
  5. BookInfo.objects.aggregate(Avg('bread'),Sum('bread'))
  6. 3.统计阅读量的最大值和最小值
  7. BookInfo.objects.aggregate(Max('bread'),Min('bread'))
  8. 4.子表查询案例
  9. sql = """select sum(a.amount) from (select * from btc_deposit WHERE wd_history_id = 0 ORDER BY amount DESC LIMIT 100) as a; """
  10. amount__sum = BtcDeposit.objects.filter(wd_history_id=0).order_by("-amount").values("amount")[:100].aggregate(coinname=Sum('amount'))
  11. # 返回一个字典:{"coinname": 25.021}
5.6 排序

我们可以使用order_by对结果进行排序

  1. BookInfo.objects.all().order_by('bread') # 升序
  2. BookInfo.objects.all().order_by('-bread') # 降序
5.7 关联查询

一对多: 一本书对应多个人物

  1. b = BookInfo.objects.get(id=1) # 获取一个书本对象
  2. b.heroinfo_set.all() # 多对应的模型类名小写_set

多对一: 多个人物出现在同一本书里

  1. h = HeroInfo.objects.get(id=1) # 获取某个人物
  2. h.hbook # 对应的关系类属性名
  3. h = HeroInfo.objects.get(id=1) # 获取某个人物
  4. h.hbook_id # 关联类属性_id
5.8 分页

如果想分页,可以直接切片查询集列表

  1. query = Node.objects.filter(**filter_dict)
  2. count = query.count() # 总个数
  3. node_list = query.order_by(*order_by_list).all()[offset: offset + limit]

如果使用Django自带的分页器,可以参考另一篇博客
【Django】paginator分页器的简单使用

6.查询结果集(QuerySet)

当查询返回的结果有多条记录时,就得到一个QuerySet,我们可以使用exists()判断是否有数据,若有则返回True,若没有则返回False。

QuerySet有两大特性,惰性执行和缓存
1.惰性执行是指当语句输入之后并不会马上执行,而是直到调用数据的时候才会真的连接数据库进行操作。
2.缓存,就是当查询一次之后它会保留结果,而不是马上销毁,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数

序列化结果集,转成字典

  1. from django.core import serializers
  2. node_list = Node.objects.filter(**filter_dict).order_by(*order_by_list).all()
  3. print("node_list:", node_list)
  4. json_data = json.loads(serializers.serialize("json", node_list)) # 转成dict
  5. print("json_data:", json_data)

上面通过serializers.serialize()方法转换出来的JSON会有一些其他信息,Django还提供了一个model_to_dict()方法进行转换

  1. from django.forms import model_to_dict
  2. node_list = Node.objects.filter(**filter_dict).order_by(*order_by_list).all()
  3. node_list = [model_to_dict(m) for m in node_list]

上面这个方法可能会不是很好,有些字段可能会不能正常序列化,也可以自己写一个方法construction_dict(),该方法同样适用于Flask

  1. def construction_dict(obj, model, field_name_list: list = None) -> dict:
  2. d = dict()
  3. # for c in field_name_list or model.__table__.columns: # flask
  4. for c in field_name_list or model._meta.fields: # Django
  5. attr_name = c if isinstance(c, str) else c.name
  6. value = getattr(obj, attr_name)
  7. if isinstance(value, datetime):
  8. value = get_date_time_str(value)
  9. if isinstance(value, Decimal):
  10. value = str(value)
  11. d[attr_name] = value
  12. return d
  13. def get_date_time_str(dt):
  14. return dt.strftime("%Y-%m-%d %H:%M:%S") if dt and isinstance(dt, datetime) else None

发表评论

表情:
评论列表 (有 0 条评论,226人围观)

还没有评论,来说两句吧...

相关阅读