美文网首页python全栈学习
Django之数据库ORM基础到进阶操作

Django之数据库ORM基础到进阶操作

作者: SlashBoyMr_wang | 来源:发表于2018-09-01 15:53 被阅读6次

    一、准备工作

    表结构如下:

    from django.db import models
    
    
    class Person(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        birth = models.DateField(auto_now = True)
    
        def __str__(self):
            return f'<Person obj:{self.id}{self.name}>'
    
    class Publisher(models.Model):
        name = models.CharField(max_length=32)
    
        def __str__(self):
            return f'<Publisher obj:{self.id}{self.name}>'
    
    class Book(models.Model):
        name = models.CharField(max_length = 32)
        price = models.DecimalField(max_digits=6,decimal_places=2)
        sale = models.IntegerField(default=-1)
        stock = models.IntegerField(default=-1)
    
        publisher = models.ForeignKey(to='Publisher')
    
        def __str__(self):
            return f'<Book obj:{self.id}{self.name}>'
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    
        books = models.ManyToManyField('Book')
    
        def __str__(self):
            return f'<Author obj:{self.id}{self.name}>'
    

    二、ORM基本操作

    1. 查询
    • 查询所有的出版社对象的集合
       models.Publisher.objects.all() 
      
    • 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
       models.Publisher.objects.get(id=1)   
      
    • 查询满足条件的所有对象,返回对象列表
      models.Publisher.objects.filter(id=1,name='sss')  
      
    • 排序
      models.Publisher.objects.all().order_by('id')    
      
    2.属性查询:
    - 无外键、多对多:
    pub_obj.id
    pub_obj.name
    
    - 外键:
    book_obj.publisher         //book所关联的出版社对象
    book_obj.publisher.id      //book所关联的出版社对象id
    book_obj.publisher_id     //book所关联的出版社对象id
    
    - 多对多:
    author_obj.books         //django封装的管理对象
    author_obj.books.all()  //作者管理的所有书籍的对象列表
    
    3. 增加
    - 普通添加:
    models.Publisher.objects.create(name='新的出版社')
    
    - 外键:
    models.Bookj.objects.create(name='新的书名',publisher_id=1)  //添加关联对象id
    models.Bookj.objects.create(name='新的书名',publisher=pub_obj)  //添加关联对象
    
    - 多对多:
    autho_obj = models.Author.objects.create(name='新的作者')
    autho_obj.books.set([1,2])  //关联对象id列表
    
    4. 删除
    models.Publisher.objects.get(id=1).delele()  //删除特定对象
    models.Publisher.objects.filter(name='xxx').delele()  //批量删除
    
    5. 修改
    - 普通修改:
    pub_obj.name = '新的名字'
    pub_obj.save()   //这种修改方式在数据库操作上会对所有字段重新赋值
    
    - 外键:
    book_obj.name = '新的书名'
    book_obj.publisher = pub_obj  //基于对象添加
    # book_obj.publisher_id = pub_obj.id  //基于关联对象id添加
    book_obj.save()
    
    - 多对多:
    author_obj.name='新的作者名'  //修改字段
    author_obj.save()
    author_obj.books.set([1,2,3])  //修改多对多关系
    

    三、ORM进阶操作

    1. 一般操作

    • 必知必会13条:
      1、all()查询所有
      ret = models.Person.objects.all()
      2、get()返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
      ret = models.Person.objects.get(id= 2)
      3、filter()它包含了与所给筛选条件相匹配的对象
      ret = models.Person.objects.filter(name='王计飞')
      ret = models.Person.objects.filter(name='哈哈')
      4、exclude()它包含了与所给筛选条件不匹配的对象
      ret = models.Author.objects.exclude(id=1)
      5、values()返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
      ret = models.Publisher.objects.values('id','name')
      6、values_list()它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
      ret = models.Book.objects.values_list('id','name','price','sale','stock','publisher_id')
      7、order_by()对查询结果排序
      ret = models.Book.objects.all().order_by('sale')
      8、reverse()对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
      ret = models.Book.objects.all().order_by('price').reverse()
      9、distinct()从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
      ret = models.Book.objects.values().distinct()
      10、count()返回数据库中匹配查询(QuerySet)的对象数量。
      ret = models.Publisher.objects.all().count()
      11、first()返回第一条
      ret = models.Book.objects.first()
      12、last()返回最后一条
      ret = models.Book.objects.last()
      13、exists()如果QuerySet包含数据,就返回True,否则返回False
      ret = models.Book.objects.filter(name='awefefe').exists()

    2、必知必会13条结果总结:

    - 返回QuerySet对象的方法有(6)
    all()
    filter()
    exclude()
    order_by()
    reverse()
    distinct()
    
    - 特殊的QuerySet (2)
    values() 返回一个可迭代的字典序列
    values_list() 返回一个可迭代的元祖序列
    
    - 返回具体对象的 (3)
    get()
    first()
    last()
    
    - 返回布尔值的方法有:(1)
    exists()
    
    - 返回数字的方法有(1)
    count()
    

    3、单表查询之神奇的双下划线

    ret = models.Book.objects.filter(price__lt=50,price__gt=20) <大于小于>
    ret = models.Book.objects.filter(price__in=[66]) <等于>
    ret = models.Book.objects.exclude(price__in=[66]) <不等于>
    ret = models.Book.objects.filter(name__contains='飞') <包含>
    ret = models.Book.objects.filter(name__icontains='飞') <不区分大小写>
    ret = models.Book.objects.filter(sale__range=[50,100]) <范围>
    ret = models.Person.objects.filter(birth__year=1993) <date字段>
    类似的还有:startswith,istartswith, endswith, iendswith 
    

    4、ForeignKey操作(Book表中设置对Publisher表的外键连接)

    - 正向查询

    对象查找(跨表查询)

    语法>>>(对象.关联字段.字段) 
    ret = models.Book.objects.first().publisher
    ret = models.Book.objects.first().publisher.id
    ret = models.Book.objects.first().publisher.name
    

    字段查找(跨表查询)

    语法>>>(关联字段__字段)
    ret = models.Book.objects.values('publisher__id','publisher__name')
    ret = models.Book.objects.values_list('publisher__id','publisher__name')
    
    - 反向查询

    对象查找(跨表查询)

    语法>>>(obj.表名_set)
    //在Book表中创建外键时没有指定related_name
    ret = models.Publisher.objects.get(id = 3).book_set.all()
    ret = models.Publisher.objects.filter(id = 3)[0].book_set.all()
    
    //在Book表中创建外键时指定related_name='books'
    ret = models.Publisher.objects.get(id = 3).books.all()
    

    字段查找(跨表查询)

    语法>>>(表名__字段)
    ret = models.Publisher.objects.values('name','book__name')
    ret = models.Publisher.objects.values_list('name','book__name')
    

    5、 ManyToManyField操作(Book表中设置对Publisher表的外键连接)

    - class RelatedManager --->关联管理器

    概念:"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。它存在于下面两种情况:1、外键关系的反向查询。 2、多对多关联关系。简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。

    几种常用的方法:
    - create()---->创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。
    ret = models.Book.objects.create(name='跟帮政扫黄',price=34,publisher_id=4)
    ret = models.Author.objects.first().books.create(name = '追风筝的人',publisher_id =1,price = 56)
    
    - add()--->把指定的model对象添加到关联对象集中。
    添加对象>>> author_objs = models.Author.objects.filter(id__lt=3)
    添加对象>>> models.Book.objects.first().authors.add(*author_objs)
    添加id>>> models.Book.objects.first().authors.add(*[1, 2])
    
    - set()--->更新model对象的关联对象。
    book_obj = models.Book.objects.first()
    book_obj.authors.set([2, 3])
    
    - remove()--->从关联对象集中移除执行的model对象
    book_obj = models.Book.objects.first()
    book_obj.authors.remove(3)
    
    - clear()--->从关联对象集中移除一切对象。
    book_obj = models.Book.objects.first()
    book_obj.authors.clear()
    
    重点注意:
    - 1、对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
    - 2、对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

    6、聚合查询和分组查询

    - 聚合查询

    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

    用到的内置函数:from django.db.models import Avg, Sum, Max, Min, Count
    ret = models.Book.objects.aggregate(Sum('price'),Count('id'),Max('price'),Min('price'),average = Avg('price'))
    
    - 分组查询
    • 统计每一本书的作者个数
    ret = models.Book.objects.all().annotate(author_num = Count('author')) for i in ret: print([i.name](http://i.name),i.author_num)
    
    • 统计出每个出版社买的最便宜的书的价格
    方法一:
    ret = models.Publisher.objects.all().annotate(cheaper = Min('book__price')).values('name','cheaper')
    
    方法二:
    ret = models.Book.objects.values_list('publisher__name').annotate(cheaper = Min('price'))
    
    • 统计不止一个作者的图书
    ret = models.Book.objects.all().annotate(num = Count('author')).filter(num__gt =1)
    
    • 根据一本图书作者数量的多少对查询集 QuerySet进行排序
    ret = models.Book.objects.all().annotate(num = Count('author')).order_by('-num')
    

    查询各个作者出的书的总价格

    ret = models.Author.objects.annotate(sum_price = Sum('books__price')).values_list('name','sum_price')
    

    - F查询和Q查询

    1.F查询:

    Django 提供 F() 来做对两个字段的值的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

    - 查询书籍销量大于库存的
    ret = models.Book.objects.filter(sale__gt=F('stock')).values('name','sale','stock')
    
    - 将所有书籍的库存加50
    ret = models.Book.objects.all().update(price = F('stock')+50)
    
    - 延伸到对char字段的操作-->在所有书名后面加上(第一版)
    from django.db.models.functions import Concat
    from django.db.models import Value
    
    ret = models.Book.objects.all().update(name = Concat(F('name'),Value('(第一版)')))
    
    
    2.Q查询

    filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

    - 作者名是王计飞或刘德凯的书
    ret = models.Book.objects.all().filter(Q(author__name='王计飞')|Q(author__name='刘德凯')).values('name','author__name')
    
    - 比较一下两者的区别(一本书的查询)
    ret = models.Book.objects.all().filter(author__name = '王计飞')
    

    补充:

    • limit_choices_to的作用是设置筛选条件,在admin中只显示筛选后的内容。

    四、Django中的常用代码段:

    1、事务操作的代码格式:

    import os
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
        import django
        django.setup()
        import datetime
        from app01 import models
         
        try:
            from django.db import transaction
            with transaction.atomic():
                操作内容
        except Exception as e:
            print(str(e))
    

    2、Django终端打印SQL语句

    在Django项目的settings.py文件中,在最后复制粘贴如下代码:
    
    ​LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }​
    

    3、在Python脚本中调用Django环境:

      import os
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
        import django
        django.setup()
        from app01 import models
        books = models.Book.objects.all()
        print(books)
    

    相关文章

      网友评论

        本文标题:Django之数据库ORM基础到进阶操作

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