美文网首页
9、Django_ORM_数据的创建以及增删改查

9、Django_ORM_数据的创建以及增删改查

作者: 猪儿打滚 | 来源:发表于2019-10-06 16:57 被阅读0次

    一、查询集QuerySet

    • 什么是查询集?
      查询集:从数据库查询得到的模型对象集合QuerySet,是一个列表
    • 什么是过滤器?
      过滤器:基于查询集得到的结果上进一步进行条件筛选过滤结果

    二、过滤器

    返回list/多个结果的过滤器
    • values = model名称.objects.all():返回所有数据;返回查询集QuerySet对象。因为是列表,所以其结果可以使用values[索引].字段名获取数据。注意不支持负索引
    • model名称.objects.retrieve():获取数据表中的所有记录,也就是返回查询集QuerySet对象
    • model名称.objects.filter():返回满足条件的数据
    • model名称.objects.exclude():返回满足条件之外的数据
    • model名称.objects.order_by():返回排序后的结果
    返回一个对象的过滤器
    • model名称.objects.get():返回一个model类,而不是str
      1.如果查询不到对应的结果, 则会抛出模型类.DoesNotExist异常
      2.如果返回多条结果,则会抛出模型类.MultipleObjectsReturned异常
    • model名称.objects.count():返回满足查询结果的总条数
    • model名称.objects.aggregate():返回集合
    • model名称.objects.exists():判断返回的查询集中是否有数据,没有则False,有则True
      PS.
      1.过滤器往往会和查询条件结合使用进行查询
      2.一般情况用 model名称.objects,但也会指定对象,比如说polls.address.
    查询集的特点
    • 非立刻执行
      1.创建查询集时,并不会访问数据库。而是直到模板中调用到数据时,才会进行数据库的访问。
    • 缓存
      1.查询集的结果会被保存下来,再次查询相同的数据时,会使用之前保存下来的结果数据
      2.每个查询集都会有一个缓存空间来保存查询结果数据
      3.切片和索引操作没有缓存可用,每次都会实际去执行sql语句
    查询集索引

    当查询集返回的是列表时,就可以使用下标的方式来获取我们想要的内容。

    def AddressAPI(request):
        # 获取第2、3、4项
        address_values = AddressInfo.objects.all()[1:3]
        # 构造上下文
        context = {F'AddressInfo:{address_values}'}
        return render(request, 'address.html', context)
    

    三、查询集的查询条件

    • 查询语句:模型属性/表字段__条件运算符=值
      1.查询语句由三部分组成:模型属性/表字段+两个下划线__+条件运算符,所以在定义属性模型/表字段时,不能定义包括多个下划线的名字
      2.想要实现SQL中的where功能,可以使用过滤器filter()exclude()get()
    • 条件运算符
      1.exact:判断相等
    address = AddressInfo.objects.filter(id__exact = 1)  # 查询id为1的地址
    

    2.contains:判断包含

    address = AddressInfo.objects.filter(name__contains = '广')  # 查询地址名称有广的地址
    

    3.startswith/endswith:以什么开头/结尾
    4.isnull:是否为null

    address = AddressInfo.objects.filter(pid__isnull = true)  # 查询pid为null的地址
    

    5.in:是否包含在范围内

    address = AddressInfo.address.filter(id__in = [1,3])  # 查询id为1或3的地址
    

    6.gt、gte、lt、lte:大于、大于等于、小于、小
    7.exclude:条件以外的数据

    address = AddressInfo.objects.filter(id__exclude = 1)   # 查询id不为1的地址
    

    8.year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行查询

    books = BookInfo.objects.filter(pub_time__year = 2000)  # 查询2000年发表的书籍
    

    9.datetime.date

    from datetime import date
    books = BookInfo.objects.filter(pub_time__gt = date(2000,1,1))  # 查询2000年1月1号以后发布的书籍
    

    10.多条件查询:或(使用|隔开查询条件)

    BookInfo.objects.filter(id__gt = 1 | pub_time__year = 2000)  # 查询id大于1或发布年份是2000年的数据
    

    11.多条件查询:与(使用,隔开查询条件)

    BookInfo.objects.filter(id__gt = 1 , pub_time__year = 2000)  # 查询id大于1,并且发布年份是2000年的数据
    

    12.链式查询:多个filter()进行查询(其它过滤器也可以这样)

    BookInfo.objects.filter(id__gt = 1).filter(pub_time__year = 2000) # 在查询id大于1的结果集上,再查询发布年份是2000年的数据
    

    13.获取查询集的第一个元素以及最后一个元素:first()last()

    BookInfo.objects.filter(id__gt = 1).first()
    BookInfo.objects.filter(id__gt = 1).last()
    

    14.排序order_by('字段/-字段')

    BookInfo.objects.filter(id__gt = 1).order_by('name') # 结果按照name排序,ascall码从小到大
    BookInfo.objects.filter(id__gt = 1).order_by('-name') # 结果按照name排序,ascall码从大到小
    BookInfo.objects.filter(id__gt = 1).order_by('id', 'name') # 结果先按照id排序,如果相同,则按照name排序
    

    PS.
    1.exact、contains、startswith、endswith这几个运算符都区分大小写,如需不区分大小写,只需要在前面加上i即可:iexact、icontains、istartswitch、iendswith

    四、F对象和Q对象

    • F对象用于两个属性进行比较,并且支持运算
      1.语法:
    from django.db.models import F
    F("属性名/表字段")
    

    2.例子
    2.1.查询评论量大于阅读量的书籍

    books = BookInfo.objects.filter(commentcount__gt = F('readcount'))
    

    2.2.查询评论量大于阅读量2倍的书籍

    books = BookInfo.objects.filter(commentcount__gt = F('readcount' * 2))
    
    • Q对象类似sql语句的where中的andor
      1.语法
    from django.db.models import Q
    # |:或
    Q(属性名/表字段1__条件运算符=值) |  Q(属性名/表字段2__条件运算符=值)   # 查询满足第一个条件或第二个条件的数据
    # ,:且
    Q(属性名/表字段1__条件运算符=值) ,  Q(属性名/表字段2__条件运算符=值)  # 查询满足第一个条件和第二个条件的数据
    # 组合
    Q(属性名/表字段1__条件运算符=值) ,  Q(属性名/表字段2__条件运算符=值)  |  Q(属性名/表字段3__条件运算符=值)  # 查询满足条件1且(条件2或条件3)的数据
    

    2.1.或:|

    books = BookInfo.objects.filter(Q(readcount__gt = 10) | Q(id__lt) = 5)  # 查询阅读量大于10或id小于5的书籍
    

    2.2.且:,

    books = BookInfo.objects.filter(Q(readcount__gt = 10) , Q(id__lt) = 5)  # 查询阅读量大于10且id小于5的书籍
    

    2.3.不等于/取反:~

    books = BookInfo.objects.filter(~Q(readcount__gt = 10) , Q(id__lt) = 5)  # 查询阅读量小于等于10且id小于5的书籍
    

    2.4.组合

    PS.如果有其它关键字条件,Q对象需要在关键字条件后面

    books = BookInfo.objects.filter(pub_time = 2000 , Q(id__lt) = 5)  # pub_time是关键字
    

    关于Q对象更详细看文章:https://www.cnblogs.com/huchong/p/8027962.html

    五、聚合函数

    • aggregate()过滤器调用聚合函数,然后返回单个对象
    • 聚合函数:Avg('属性名/表字段')Max('属性名/表字段')Min('属性名/表字段')Sum('属性名/表字段')Count('属性名/表字段')。使用Count('属性名/表字段')时,一般情况下是直接调用,不需要使用aggregate()函数
    • 聚合函数在django.db.models导入
    • 例子(注意上下文字典中,总阅读量的key的书写规则)
    from django.db.models import Sum
    
    def books(request):
        # 统计所有书籍的总阅读量
        readcount = BookInfo.objects.aggregate(Sum('readcount'))
        # 构造上下文
        context = {'readcount': readcount}
        return  render(request, 'Book/book.html', context)
    

    六、关联查询(objects前面用的是哪个class,返回的就是哪个class对象)

    一对多、多对多关联查询(基础关联)
    • 查询方老师所教的所有课程
     # 先查询方老师
    teacher = Teacher.objects.get(nickname = '方老师')
    # 再通过方老师查询所有相关的任务信息
    classInfo = teacher.classinfo_set.all()
    
    • 查询python课程的老师
    # 先查询课程
    class = ClassInfo.object.get(title = 'python课程')
    # 再通过关联查询对应的老师
    teacher = class.teacher
    
    内连接查询
    • 语法:外键字段名__从表字段名__条件关联模型类名小写__属性名__运算符=值,结果和sql中的inner join相同(内连接)
    • 查询书名为"红楼梦"的所有人物信息(peopleInfo)
      通过书找关联的人
    # 原始内连接sql语句:
    select p.name, b.name from peopleinfo as p inner join bookinfo as b on p.book_id = b.id where b.name = "红楼梦";
    

    对应语句:

    peopleInfos = PeopleInfo.objects.filter(book__name='红楼梦')
    
    • 查询书籍中人物的描述包含"红"的书籍
      通过人找关联的书
    bookInfos = BookInfo.books.filter(peopleinfo__description__contains='红')
    
    自关联查询

    自关联的表结构:对于地区信息、分类信息等数据,表结构非常类似,每个表的数据量十分有限,为了充分利用数据表的大量数据存储功能,可以设计成一张表,内部的关系字段指向本表的主键
    说明:关系属性使用self指向本类,要求null和blank允许为空,因为一级数据是没有父级的
    更多看之前的文章:https://www.jianshu.com/p/08c1be3dc9b2

    七、LIKE语句中转义百分符号和下划线

    在sql语句中,%有特殊的作用,Django可以转义%_,这样就可以和普通字符一样使用

    xxx.objects.filter(headline__contains='%')
    # 相当于sql:
    SELECT ... WHERE headline LIKE '%\%%';
    

    八、创建数据/生成数据表中的数据

    • 创建和保存对象
    #### 方法1
    # 1.创建模型类对象,此时sql还未执行
    one_value = Userinfo(username='hello', password='hi')
    # 2.调用save方法,执行sql语句,生成数据
    one_value.save()
    
    #### 方法2
    # 执行sql语句,生成数据,返回的是模型类对象
    Userinfo.objects.create(username='hi', password='hello')
    
    • 保存外键字段
      保存外键字段和保存普通字段一样,只不过给外键字段赋值的时候迅速要注意类型要正确
    • 保存多对多字段
      需要调用add()方法,而不是直接给属性赋值,不过不需要调用save()方法
    from .model.animal import Animal
    from .model.cat import Cat
    
    animal = Animal.objects.get(pk = 1)
    cat1 = Cat.objects.create(named='xiaomi')  
    cat2 = Cat.objects.create(named='xiaohei')
    
    animal.cats.add(cat1, cat2)    # 保存多对多字段
    

    八、修改数据和更新数据

    • 修改数据:先获取数据,然后修改数据,再保存数据(一般用于外键/ForeignKey的修改)
    value = Animal.objects.get(id=1)
    value.namede = 'haha'
    value.save()
    
    • 更新数据:update()
      1.可以批量为QuerySet中所有的对象进行更新操作
      2.只能对普通字段和ForeignKey字段使用
      3.对ForeignKey字段使用时,需要设置新值为想要指向的新模型实例
    # 普通字段
    Animal.objects.filter(id=1).update(named = 'hahaha')
    # ForeignKey字段
    c = Cat.objects.get(id=2)  # 想要指向的新模型实例
    Animal.objects.all().update(cat=c)
    
    • update()方法会直接转换成一个sql语句,并立刻批量执行,并且不会运行模型的save()方法。如果想要保存QuerySet中的每个条目并确保每个实例的save()方法都被调用,你不需要使用任何特殊的函数来处理。只需要迭代它们并调用save()方法:
    for item in my_queryset:
        item.save()
    
    • update方法可以配合F表达式。这对于批量更新同一模型中某个字段特别有用。例如增加Blog中每个Entry的pingback个数:
      Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)。然而,与filterexclude子句中的F()对象不同,在update中不可以使用F()对象进行跨表操作,只可以引用正在更新的模型的字段。如果尝试使用F()对象引入另外一张表的字段,将抛出FieldError异常:
    # THIS WILL RAISE A FieldError
    >>> Entry.objects.update(headline=F('blog__name'))
    

    九、删除数据

    先获取数据,再删除数据

    value = Animal.objects.get(id=1)
    value.delete() # 该方法将返回被删除对象的总数量和一个字典,字典包含了每种被删除对象的类型和该类型的数量
    # 支持批量删除
    Animal.objects.filter(named='haha').delete()
    
    • 注意
      delete()是唯一没有在管理器上暴露出来的方法。这是刻意设计的一个安全机制,用来防止意外地请求类似Animal.objects.delete()的动作,导致不慎删除了所有的对象数据。如果你确实想删除所有的对象,你必须明确地请求一个完全的查询集,如:
    Animal.objecets.all().delete()
    

    PS.本文参考:
    https://blog.csdn.net/kan2016/article/details/82868636/https://www.cnblogs.com/huchong/p/8027962.html

    相关文章

      网友评论

          本文标题:9、Django_ORM_数据的创建以及增删改查

          本文链接:https://www.haomeiwen.com/subject/yvchpctx.html