zoukankan      html  css  js  c++  java
  • Django中orm相关操作

    必知必会13条
    示例model
    单表双下划线
    外键相关
    多对多相关
    聚合和分组
    F、Q
    orm性能相关
    事务

    必知必会13条

    import os
    import django
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    django.setup()
    from app01 import models
    
    # 一、all 查询所有的数据,返回的是一个对象列表(QuerySet)
    ret = models.Person.objects.all()
    print('all',ret)
    # 二、get 获取一个存在且唯一的数据,返回的是对象,没有或者是多个就报错
    ret = models.Person.objects.get(pid=4)
    print('get',ret.name)
    # 三、filter 筛选出符合条件的,返回的是对象列表
    ret = models.Person.objects.filter(age=18)
    print('filter',ret)
    # 四、exclude 获取不满足条件的数据,返回的是对象列表
    ret = models.Person.objects.exclude(name='alex')
    print('exclude',ret)
    for i in ret:
        print(i.name)
    # 五、order_by 排序,默认为升序,字段前加-为降序
    ret = models.Person.objects.all().order_by('pid')
    print('order_by',ret)
    for i in ret:
        print(i.pid)
    # 六、reverse 对排完序的对象列表进行反转
    ret = models.Person.objects.all().order_by('pid').reverse()
    print('reverse',ret)
    for i in ret:
        print(i.pid)
    # 七、values 不指定字段,获取数据所有的字段和值,返回的是对象列表(QuerySet)[{},{}]
    ret = models.Person.objects.all().values()
    print('values',ret)
    # 指定字段,获取到数据指定的字段名和值,返回的是对象列表(QuerySet)[{},{}]
    ret = models.Person.objects.all().values('name', 'age')
    print('values',ret)
    # 八、values_list 不指定字段,获取所有数据字段的值,返回的是对象列表(QuerySet)[{},{}]
    ret = models.Person.objects.all().values_list()
    print('values_list',ret)
    # 指定字段,获取到数据指定的字段的值,返回的是对象列表(QuerySet)[{},{}]
    ret = models.Person.objects.all().values_list('name', 'age')
    print('values_list',ret)
    # 九、distinct 对获取到的数据进行去重,返回的是对象列表(QuerySet)[{},{}]
    ret = models.Person.objects.values('age').distinct()
    print('distinct',ret)
    # 十、count 对获取到的数据进行计数
    ret = models.Person.objects.filter(age=18).count()
    print('count',ret)
    # 十一、first 获取第一个元素
    ret = models.Person.objects.all().first()
    print('first',ret.pid)
    # 十二、last 获取最后一个元素
    ret = models.Person.objects.all().last()
    print('last',ret.pid)
    # 十三、exists 判断数据是否存在,返回的是对象列表,如果对象不存在,返回的是空对象列表
    ret = models.Person.objects.filter(pid=1)
    print('exists',ret)
    
    • 返回对象列表
      • all
      • filter
      • exclude
      • order_by
      • reverse
      • values [{},{}]
      • values_list [(),()]
      • distinct [{},{}]
    • 返回对象
      • get
      • first
      • last
    • 返回数字
      • count
    • 返回布尔值
      • exists

    示例model模型

      from django.db import models
      
      class MyCharField(models.Field):
          """
          自定义的char类型的字段类
          """
      
          def __init__(self, max_length, *args, **kwargs):
              self.max_length = max_length
              super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
      
          def db_type(self, connection):
              """
              限定生成数据库表的字段类型为char,长度为max_length指定的值
              """
              # return 'char(%s)' % self.max_length
              return f'char{self.max_length}'
      class Person(models.Model):
          pid = models.AutoField(primary_key=True)
          name = models.CharField(db_column='nick', max_length=32, )
          age = models.IntegerField(null=True, default=18)
          phone = MyCharField(verbose_name='电话', max_length=11, blank=True, unique=True)
          birth = models.DateTimeField(auto_now_add=True)
          sex = models.BooleanField(choices=((True, '男'), (False, '女')))
          gender = models.IntegerField(choices=((1, '男'), (2, '女'), (3, '不详')))
          
          def __str__(self):
              return f'{self.pid}-{self.name}-{self.age}'
          
          class Meta:
              db_table = 'person'  # 数据库中表的名字
              verbose_name = '个人信息'  # admin中的表名称
              verbose_name_plural = '所有用户信息'
              index_together = [
                  ('name', 'age')
              ]  # 联合索引,查询两个存在的字段,全部查询速度快,单查左边速度快
              unique_together = ('name', 'age')  # 联合唯一约束,查询两个存在的字段
      
      
      class Publisher(models.Model):
          name = models.CharField(max_length=32)
      
          def __str__(self):
              return f'<Publisher object>:{self.id}-{self.name}'
      
      class Book(models.Model):
          name = models.CharField(max_length=32)
          pub = models.ForeignKey('Publisher', on_delete=models.CASCADE, related_name='book')
      
          def __str__(self):
              return f'<Book object>:{self.id}-{self.name}-{self.pub.name}'
      
      class Author(models.Model):
          name = models.CharField(max_length=32, verbose_name='作者')
          books = models.ManyToManyField('Book')
      
          def __str__(self):
              return f'<Author object>:{self.id}-{self.name}'
    

    单表查询之神奇的下划线

    import os, django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    django.setup()
    from app01 import models
    
    ret = models.Person.objects.filter(pid__lt=5)  # less than
    ret = models.Person.objects.filter(pid__lte=5)  # less than equal
    
    ret = models.Person.objects.filter(pid__gt=5)  # greater than
    ret = models.Person.objects.filter(pid__gte=5)  # greater than equal
    
    ret = models.Person.objects.filter(pid__in=[5, 6, 11]) # 判断在列表里面
    ret = models.Person.objects.exclude(pid__in=[5, 6, 11])
    ret = models.Person.objects.filter(pid__range=[1, 10]) # 判断范围在1-10,包括10.
    
    ret = models.Person.objects.filter(name__contains='a') # 判断name属性里包不包含a
    ret = models.Person.objects.filter(name__icontains='a') # 大小写不敏感
    
    ret = models.Person.objects.filter(name__startswith='s') # 判断name是否已a开头
    ret = models.Person.objects.filter(name__istartswith='s') # 大小写不敏感
    
    ret = models.Person.objects.filter(name__endswith='t') # 判断name是否以t结尾
    ret = models.Person.objects.filter(name__iendswith='t') # 大小写不敏感
    
    ret = models.Person.objects.filter(birth__year='2020') # 判断年是不是2020
    ret = models.Person.objects.filter(birth__contains='-04-') # 判断月份是不是4月
    # ret = models.Person.objects.filter(birth__month='02')
    # ret = models.Person.objects.filter(birth__day='21')
    
    ret = models.Person.objects.filter(age__isnull=True) # 判断age这个字段是否为空
    
    print(ret)
    

    外键(ForeignKey)查询的相关操作

    import os, django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    django.setup()
    from app01 import models
    
    # 基于对象的查询
    # 正向查询
        book_obj = models.Book.objects.get(id=1)  # 获取对应的book对象
        print(book_obj.pub)  # 关联的出版社对象
        print(book_obj.pub_id)  # 关联的出版社id
    # 反向查询
        pub_obj = models.Publisher.objects.get(id=1)
        print(pub_obj)  # 出版社对象
        # 不指定related_name,使用类名_set获取到关系关联对象,在通过.all()获取到对应的所有对象
        print(pub_obj.book_set.all())  # pub_obj.book_set关系关联对象,类名_set.all()得到出版社所有的书籍
        print(type(pub_obj.book_set))  # pub_obj.book_set关系关联对象
        # 指定related_name,使用related_name的值获取到关系关联对象,在通过.all()获取到对应的所有对象
        print(pub_obj.book.all())  # pub_obj.book_set关系关联对象
    
    # 基于字段的查询
        ret = models.Book.objects.filter(pub__name__contains='晓龙出版社')
        # 不指定related_name,直接类名小写__name
        ret = models.Publisher.objects.filter(book__name='少年阿兵')
        # 指定related_name,使用related_name的值 + __name
        ret = models.Publisher.objects.filter(book__name='少年阿兵')
        # 指定了related_query_name,使用related_query_name的值
        # 不指定related_query_name,使用related_name的值
        print(ret)
    
    ###################  外键  ###################
    
    pub_obj = models.Publisher.objects.get(id=1)
    # set  add  create  [id,id]
    pub_obj.books.set(*models.Book.objects.filter(id__in=[1,2,3,4] ))
    pub_obj.books.add(*models.Book.objects.all())
    
    # remove clear  外键字段参数 null=True 才有这两个方法
    pub_obj.books.clear()
    

    多对多(ManyToManyField)查询的相关操作

    import os
    import django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    django.setup()
    from app01 import models
    
    author_obj = models.Author.objects.get(id=8)  # 获取id=8的作者对象
    print(author_obj.books.all())  # 获取到关系关联对象的所有数据
    # 关系关联对象的方法
    # all 获取所有的数据
    # set 设置多对多的关系,[id,id]/[对象,对象]
    author_obj.books.set([1,4])  # 通过关系关联对象给多对多表里author_id=8设置book_id
    author_obj.books.set(*models.Book.objects.filter(id__in=[2,4]))
    
    # add 添加多对多关系,[id,id]/[对象,对象]
    author_obj.books.add(4,3,2)  # 通过关系关联对象给多对多表里author_id=8添加book_id
    author_obj.books.add(*models.Book.objects.filter(id__in=[1,2,3,4]))
    
    # remove 删除多对多关系,[id,id]/[对象,对象]
    author_obj.books.remove(1)
    author_obj.books.remove(*models.Book.objects.filter(id__in=[4]))
    
    # clear 清空多对多关系
    author_obj.books.clear()
    
    # create 新建一个book对象与当前的对象建立关系,在book表新建一个对象,并且和当前的作者进行关联
    author_obj.books.create(name='alexdsb',pub_id=2)
    
    
    book_obj = models.Book.objects.get(id=1)  # 获取到id=1的book对象
    print(book_obj.author_set.all())  # 通过反向查询到对应的作者对象
    book_obj.author_set.set([8,9,10])  # 通过作者对象给多对多表里book_id=1的设置author_id
    

    聚合与分组查询

    import os
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    import django
    django.setup()
    from app01 import models
    from django.db.models import Max, Min, Avg, Count, Sum  # 导入聚合函数
    
    聚合 aggregate,终止子句
      ret = models.Book.objects.aggregate(Count('price'))  # 统计有多少本书
      print(ret)
      # 统计出book_id大于3的书里的最大价格和最低价格
      ret = models.Book.objects.filter(id__gt=3).aggregate(max=Max('price'),min=Min('price'))
      # 统计所有书里最大价格和最低价格
      ret = models.Book.objects.all().aggregate(max=Max('price'),min=Min('price'))
    	print(ret)
    分组 annotate 注释,给聚合之后的结果添加一个字段
      # 1.统计每一本书的作者个数
      ret = models.Book.objects.annotate(Count('author__name')).values()
      for i in ret:
          print(i)
      # 2.统计出每个出版社卖的最便宜的书
      # 方法一、
      ret = models.Publisher.objects.annotate(Min('book__price')).values()
      for i in ret:
          print(i)
      # 方法二、
      ret = models.Book.objects.values('pub','pub__name').annotate(Min('price'))
      for i in ret:
          print(i)
      # 3.统计不止一个作者的图书
      ret = models.Book.objects.annotate(count=Count('author__name')).filter(count__gt=1)
      print(ret)
      # 4.根据一本图书作者的数量的多少对查询集 进行排序
      # 方式一
      ret = models.Book.objects.annotate(count=Count('author__name')).order_by('-count')
      .values()
      # 方式二
      ret = models.Author.objects.values('books','books__name').annotate(count=Count('name'))
      .order_by('-count')
      for i in ret:
          print(i)
      # 5.查询各个作者出的书的总价格
      # 方式一
      ret = models.Author.objects.annotate(sum=Sum('books__price')).values()
      # 方式二
      ret = models.Book.objects.values('author','author__name').annotate(sum=Sum('price'))
      for i in ret:
          print(i)
    

    F和Q查询

    import os
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    import django
    django.setup()
    from app01 import models
    from django.db.models import F, Q
    
    F操作 - 用于字段与字段之间的比较
      ret = models.Book.objects.filter(stock__gt=50)  # 统计库存大于50的书籍
      for i in ret:
          print(i)
      ret = models.Book.objects.filter(sales__gt=F('stock'))  # 统计销量大于库存的书籍
      for i in ret:
          print(i)
      # ret = models.Book.objects.all().update(stock=F('stock')+10)  # 给所有书籍的库存加10
      # ret = models.Book.objects.all().update(stock=F('stock')-10)  # 给所有书籍的库存减10
      
    Q操作
      # 与 &
      # 或 |
      # 非 ~
      # 获取id小于3或者id大于4的书籍
      # 方式一、用exclude排除
      ret = models.Book.objects.exclude(id__gte=3,id__lte=4)
      print(ret)
      # 方式二、用Q操作
      ret = models.Book.objects.filter(Q(id__lt=3)|Q(id__gt=4))
      print(ret)
    
      # 获取id小于3或者id大于4,且书名以‘少年’开头的书籍
      ret = models.Book.objects.filter(Q(id__lt=3) | Q(id__gt=4) & Q(name__startswith='少年'))
      print(ret)
      # 获取id小于3=,且书名以‘少年’开头的书籍
      ret = models.Book.objects.filter(Q(id__lt=3) & Q(name__startswith='少年'))
      print(ret)
    
      # 获取id小于3或者id大于4,且书名不以‘少年’开头的书籍
      ret = models.Book.objects.filter(Q(id__lt=3) | Q(id__gt=4) & ~Q(name__startswith='少年'))
      print(ret)
      # 获取id小于3=,且书名不以‘少年’开头的书籍
      ret = models.Book.objects.filter(Q(id__lt=3) & ~Q(name__startswith='少年'))
      print(ret)
    

    orm性能相关

    Debug_tool_bar

    1 能用values的尽量不用对象.的形式来获取数据
        students = models.Student.objects.all().values('classes__name') #链表查询,查询一次 queryset[{'classes__name':'27期'},{'classes__name':'27期'},{'classes__name':'27期'}]
        for s in students:
            # print(s.classes.name)  #查询多次,每次点都进行一次sql查询,效率低
            print(s['classes__name'])  
    
            
    2 通过select_related直接进行连表查询  针对一对一和一对多
        students = models.Student.objects.all().select_related('classes')
        for s in students:
            print(s.classes.name)
    
    3 通过prefetch_related子查询来完成
        students = models.Student.objects.all().prefetch_related('classes')
        for s in students:
            print(s.classes.name)
            
    4 only和defer
    
    		当我们进行orm查询的时候,你通过翻译出来的sql语句可以看到,每次查询都是查询了每个字段的数据,所以我们通过only和defer,可以指定查询哪些字段数据
        all_students = models.Student.objects.all().only('name')#只要这个字段数据
        all_students = models.Student.objects.all().defer('name')#排除,除了这个字段其他字段数据都要
    

    事务

    import os
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day50_orm.settings")
    import django
    django.setup()
    from app01 import models
    from django.db.models import F
    from django.db import transaction
    
    try:
      with transaction.atomic():
          models.Book.objects.all().update(stock=F('stock') + 20)
          models.Book.objects.all().update(sales=F('sales') - 20)
    except Exception as e:
      print(e)
    
  • 相关阅读:
    github上用golang写的项目
    golang项目:goa和micro
    lua远程调试,跨平台支持N多平台
    谈谈逆向android里面的so
    windows server 2016安装
    skynet记录7:第一个服务logger和第二个服务bootstrap
    skynet记录7:服务(c和lua)
    skynet记录6:定时器
    skynet记录5:框架综述
    skynet记录4:简单demo分析
  • 原文地址:https://www.cnblogs.com/zuoxiaodragon/p/13566281.html
Copyright © 2011-2022 走看看