• 9_19模型层的操作


    一。配置settings。

      如果是queryset对象 那么可以点query直接查看该queryset的内部sql语句

      将以下代码放入settings中。就可以实现当使用orm时查看sql语句:

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
                },
            },
        'loggers': {
            'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
                },
            }
        }

    二。双下划线查询。

      在orm过滤查询中,有基于双下划线的查询,可以节省时间。

      1.大于:__gt

      可以匹配大于这个数值的数:

    res = models.Book.objects.filter(price__gt=89)

      2.小于__lt

      匹配小于这个数值的数据:

    res = models.Book.objects.filter(price__lt=89)

      3.大于等于__gte

      匹配大于等于这个数值的数:

    res = models.Book.objects.filter(price__gte=89)

      4.小于等于__lte

      匹配小于等于这个数值的数:

    res = models.Book.objects.filter(price__lte=89)

      5。__in

      匹配在后面这个数列中的所有值的数据/。

    res = models.Book.objects.filter(price__in=[89,123,454])

      6.__range(x,y)

      匹配在这个范围中的所有数据。包括头和尾。

    res = models.Book.objects.filter(price__range=[55,123])

      7.__contains

      模糊匹配,字段中包函这个字段的数据。

    res = models.Book.objects.filter(title__contains='p')

      这个匹配区分大小写。下面这个方法不区分。

      8.__icontains

    res = models.Book.objects.filter(title__icontains='P')

      9.__startswith

      匹配开头时这个数值的数据

    res = models.Book.objects.filter(title__startswith='')

      10.__endswith

      匹配结尾这个数值的数据

    res = models.Book.objects.filter(title__endswith='')

      11.__year

      匹配时间数据类型中年份为该年的数据:

    res = models.Book.objects.filter(publish_date__year=2019)
    res = models.Book.objects.filter(publish_date__month=9)

      当然,其中还有其他过滤日期的方法。

    (自己理解): 

      对于像onetoonefield,foreign,manytomany等字段,都是 有母子之分的。

      也就是说这个虚拟字段在哪个表里,哪个表就是子表。

      而我们把根据子表查询母表时的动作叫正向查询。

        正向查询都是按找字段名查找。

      根据母表数据查询子表数据的动作叫反向查询。

        反向查询都是按照表名小写_set查找。

      得到的结果就是那个表的对象。

      而在1对1 的时候不需要加_set,只需要小写就行。

    三。关于外键的增删改。

      1.一对多

      增:

      可以按照id值传入外键:

    models.Book.objects.create(title='三国演义',price=189.99,publish_id=1)

      也可以将那个对象传入:

    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj)

      改:

      将id数字传入:

    models.Book.objects.filter(pk=1).update(publish_id=3)

      可以将对象传入:

    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.filter(pk=1).update(publish=publish_obj)

      删:

      删除的时候,默认都是级联操作。也即是这个数据删除了它所关联的外键也删除。

    models.Publish.objects.filter(pk=2).delete()

      2,多对多字段的增删改。

      增:

      增加操作多借助于add(),是一个正对query对象的方法。

    #要给主键为1的书籍添加两个作者
    book_obj = models.Book.objects.filter(pk=1).first()
    print(book_obj.authors)  
    # 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
    book_obj.authors.add(1)
    book_obj.authors.add(2,3)

      add()也支持传入对象,添加对象:

    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.add(author_obj)
    book_obj.authors.add(author_obj1,author_obj2)

      改:

      改操作借助于函数set()

      set支持传入数据:

    将主键为1的书籍对象 作者修改为2,3
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.set([2,])
    book_obj.authors.set([2,3])

      也支持传入对象:

    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.set([author_obj,])
    book_obj.authors.set([author_obj, author_obj1, author_obj2])

      但是set中要是一个可迭代对象。但不能混合使用。

      删:

      删除操作使用的是remove函数:
      可以支持数字:

    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.remove(3)
    book_obj.authors.remove(1,2)

      也支持对象:

    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.remove(author_obj)
    book_obj.authors.remove(author_obj1,author_obj2)

      除了remove之外,还可以使用clear,将这个对象的所有联系都清空。

    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.clear()  # 清空当前书籍与作者的所有关系

      这些操作也支持_set反向操作。

    四。基于对象的跨表查询。

      多表查询的方法可以先将一个条件对象找到,通过他下面的虚拟字段或者起子表_set的方法获取表对象,在提取想要的信息。

      例子:

        查询作者是jason的家庭住址
        author_obj = models.Author.objects.filter(name='jason').first()
        print(author_obj.author_detail.addr)
    
    
        查询出版社是东方出版社出版的书籍
        publish_obj = models.Publish.objects.filter(name='东方出版社').first()
        # print(publish_obj.book_set)  # app01.Book.None
        print(publish_obj.book_set.all())
    
        查询作者是jason的写过的所有的书籍
        author_obj = models.Author.objects.filter(name='jason').first()
        print(author_obj.book_set)  # app01.Book.None
        print(author_obj.book_set.all())

      注意,在获取了表之后,可以继续对其使用对表对象使用的一切方法。

    五。基于双下划线的跨表查询。

      双下划线作用于任何关于表的字段的获取,其可以获取另一个它关联的表的字段数据。

      双下划线不分子母表。

      values()函数相当于原生sql语句中的select后面的值。其返回的也是一个queryset对象。其中传入的是字段

      例子:

    查询jason这个作者的年龄和手机号
    正向
    res = models.Author.objects.filter
    (name='jason').values('age','author_detail__phone') print(res) 反向 res1 = models.AuthorDetail.objects.filter
    (author__name='jason').values('phone','author__age')

      例子2:

    # 查询手机号是130的作者年龄
    # 正向
    res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
    print(res)
    # 反向
    res1 = models.Author.objects.filter(author_detail__phone=130).values('age')

      只要表里有外键字段,就可以无限跨多张表:

    res1 = models.Book.objects.filter(pk=1).values('外键字段1__外键字段2__外键字段3__普通字段')

    六。聚合查询:

      聚合查询和sql原生语句差不都:

      1.Sum()求和

      2.Avg()求平均值

      3.Count()计数

      4.Max()最大值

      5.Min()最小值

    from django.db.models import Max,Min,Count,Avg,Sum
    res = models.Book.objects.aggregate(Sum('price'))
    res1 = models.Book.objects.aggregate(Avg('price'))
    res2 = models.Book.objects.aggregate(Count('price'))
    res3 = models.Book.objects.aggregate(Max('price'))
    res4 = models.Book.objects.aggregate(Min('price'))
    res5 = models.Book.objects.aggregate(Max('price'),  
      Min('price'),Count('pk'),Avg('price'),Sum('price'))

      其中aggregate就是使用聚合函数,其中也支持双下划线跨表查询。

    七。分组查询。

      分组查询使用annotate()

      这个函数中可以使用聚合函数,使用聚合函数产生的结果可以给他起别名,再通过value展示。

    res = models.Publish.objects.annotate
      (mmp = Min('book__price')).values('name','mmp')

      如果annotate之前不使用value进行指定字段,就将这个表的id作为分组对象。指定了value就将value中的字段进行分组。

      例子:

    查询各个作者出的书的总价格
    res = models.Author.objects.annotate(
      sp=Sum('book__price')).values('name','sp')

    八。f查询与q查询。

      f。将数据库中的数据取出转化成可操作的。

      当你需要查询一个值的数据两端都是数据库中的值时。可以使用f将后面那个值包起来,这样系统会根据记录一条条比对:

    from django.db.models import F
    res = models.Book.objects.filter(kucun__gt=F('maichu'))
    
    # 将书籍库存数全部增加1000
    models.Book.objects.update(kucun=F('kucun')+1000)

      这个操作可以将数据库中本来的数据拿出来使用f操作进行转换,转换成课进行操作的对象:

     # 把所有书名后面加上'新款'
    from django.db.models.functions import Concat
    from django.db.models import Value
    ret3 = models.Book.objects.update
        (title=Concat(F('title'), Value('新款')))
    models.Book.objects.update(title = F('title')+'新款')  # 不能这么写

      其中concat就是拼接字符串操作(再数据库中),而value就是将字符串转化成可操作的数据。

      q。将数据库的数据取出,转化成可进行逻辑比较的。

      如果需要将两个字段的数据一起匹配时可以使用q进行操作。

      例子:

    from django.db.models import Q
    查询书籍名称是三国演义或者价格是444.44
    res = models.Book.objects.filter(title='三国演义',price=444.44)  # filter只支持and关系
    res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444))  # 如果用逗号 那么还是and关系
    res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444))
    res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))
    # 非操作。

      在q前面加上~表示非操作。

      衍生:

      当需要使用字符串作为表字段名进行操作的时候,可以使用q。

      也就是说不会提前知道字段名,只知道该字段是个字符串。

        # Q高级用法
        q = Q()
        q.connector = 'or'  # 修改查询条件的关系   默认是and
        q.children.append(('title__contains','三国演义'))  # 往列表中添加筛选条件
        q.children.append(('price__gt',444))  # 往列表中添加筛选条件
        res = models.Book.objects.filter(q)  # filter支持你直接传q对象  但是默认还是and关系
        print(res)

    补充:

      1.在一对一字段中OnoToOneField操作可以用ForeignKey代替(ForeignKey(unique=True))

      2.虚拟字段除了关联第三张表之外,还能帮助orm跨表查询。

  • 相关阅读:
    Spring Boot 配置文件 bootstrap vs application 到底有什么区别?
    一份完整的 Java 成神路线图,值得收藏!
    12 岁开始学编程,17 岁总结了 7 个重要教训!
    想成为顶尖 Java 程序员?先过了下面这些问题!
    Dubbo面试20问!这些题你都遇到过吗?
    yum安装出现No package crontabs available解决办法
    表结构设计方法
    后端token认证模板
    vue 用户登录 路由拦截 vuex cookie
    pyharm无法安装包的问题
  • 原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/11552765.html
Copyright © 2020-2023  润新知