代码改变世界

Django 之 模型层ORM操作

2019-10-24 22:24  在上海的日子里  阅读(205)  评论(0编辑  收藏  举报

目  录

  • ORM查询配置文件和测试环境搭建

      • 配置文件(打印orm操作时显示sql语句)   Django测试环境搭建
  • 单表查询

      • 必知必会13条      神奇的双下划线查询
  • 多表查询

      • 子查询和连表查询      外键字段的增删改查       表与表之间的关联查询

 

 

一、ORM查询相关配置文件和django测试环境配置

1、想要在打印orm操作时显示原生的SQL语句,需要在settings.py  文件中添加如下代码:

 """
        如果你向查看orm语句内部真正的sql语句有两种方式
            1.如果是queryset对象 可以直接点query查看
            2.配置文件中 直接配置
            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查询语句中显示原生的SQL语句有两种方法:

一种是如上配置文件;

一种就是QuerySet对象,直接点Query查看,

只要是queryset对象就可以无限制的点queryset对象的方法
queryset.filter().filter().filter()

 

2、Django测试环境搭建

从manage.py 文件中拷如下代码,并添加 import django    和 django.setup()  两行代码

import os

        if __name__ == "__main__":
            os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_search.settings")
            import django
            django.setup()
            # 你就可以在下面测试django任何的py文件

 

二、单表查询

必知必会13 条, 神奇的双下划线查询

from django.test import TestCase

# Create your tests here.
import os


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

    # 单表操作
    # 增删改查
    #
    # models.Book.objects.create(title='金瓶霉',price=123.23,publish_date='2019-10-24')
    # from datetime import date
    # ctime = date.today()
    # book_obj = models.Book(title='三国演义',price=666.66,publish_date=ctime)
    # book_obj.save()

    #
    # models.Book.objects.filter(pk=1).update(price=999.66)

    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.title = '不符合社会主义核心价值观'
    # book_obj.save()




    # 删除
    # models.Book.objects.filter(pk=1).delete()

    #
    # 1.all()  查询所有           QuerySet
    # res = models.Book.objects.all()  # 惰性查询
    # print(res)
    # for i in res:
    #     print(i.title)

    # 2.filter()                  QuerySet
    # res = models.Book.objects.filter(pk=2)
    # print(res)

    # 3.get()                        数据对象本身

    # 4.first()     拿第一个
    # res = models.Book.objects.all()
    # print(res)
    # print(res.first())
    #5. last()     拿最后一个
    # res = models.Book.objects.all()
    # print(res)
    # print(res.last())

    # 6.exclude  除此之外        QuerySet
    # res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
    #     # # <QuerySet []>
    #     # print(res)

    # 7.values  QuerySet    列表套字典
    # res = models.Book.objects.values('title')
    # for r in res:
    #     print(r.get('title'))


    # 8.values_list  QuerySet    列表套元组
    # res = models.Book.objects.values_list('title')
    # print(res)


    # 9.count()  统计数据的个数
    # res = models.Book.objects.count()
    # res1 = models.Book.objects.all().count()
    # print(res,res1)

    # 10.distinct() 去重
    """去重:数据必须是一模一样的情况下才能去重"""
    # res = models.Book.objects.all().distinct()
    # res1 = models.Book.objects.values('title','price').distinct()
    # print(res1)
    # 11.order_by()
    # res = models.Book.objects.order_by('price')  # 默认是升序
    # # res1 = models.Book.objects.order_by('-price')  # 加负号就是降序
    # print(res)
    # 12.reverse()  前面必须是先结果排序才可以反转
    # res = models.Book.objects.order_by('price').reverse()
    # print(res)
    # 13.exists()  一点卵用没有
    # res = models.Book.objects.filter(pk=1).exists()
    # print(res)



    """神奇的双下划线查询"""
    # 查询价格大于200的书籍
    # res = models.Book.objects.filter(price__gt=200)
    # 查询价格小于200的书籍
    # res = models.Book.objects.filter(price__lt=200)
    # print(res)
    # 查询价格大于或者等于200的书籍
    # res = models.Book.objects.filter(price__gte=200)
    # res1 = models.Book.objects.filter(price__lte=200)
    # print(res,res1)

    # 价格是200 或者是123.23 或者666.66
    # res = models.Book.objects.filter(price__in=[200,123.23,666.66])
    # print(res)
    # 价格在200 到700之间的书籍
    # res = models.Book.objects.filter(price__range=(200,666.66))  # 顾头不顾尾
    # print(res)


    # 模糊匹配
    """
    like
        %
        _
    """
    # 查询书籍名称中包含p的
    # res = models.Book.objects.filter(title__contains='p')  # 区分大小写
    # print(res)
    # 忽略大小写
    # res = models.Book.objects.filter(title__icontains='p')  # 忽略大小写
    # print(res)


    # 查询书籍名称是以三开头的书籍
    # res = models.Book.objects.filter(title__startswith='三')
    # res1 = models.Book.objects.filter(title__endswith='P')
    # print(res1)


    # 查询出版日期是2019年的书籍
    # res = models.Book.objects.filter(publish_date__year='2019')
    # 查询出版日期是10月的书籍
    # res = models.Book.objects.filter(publish_date__month='10')

三、多表查询

import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "many_search.settings")
    import django
    django.setup()
    from app01 import models
    # 一对多字段增删改查
    # models.Book.objects.create(title='三国演义',price=123.23,publish_id=1)  # publish_id直接传出版社主键值

    # publish_obj = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.create(title='水浒传',price=123.23,publish=publish_obj)  # publish直接传出版社数据对象

    #
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj.publish)  # 获取到当前所对应的出版社对象
    # print(book_obj.publish_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()
    # 默认也是级联更新 级联删除

    # 多对多字段的增删改查

    # 给主键为3的书籍添加两个作者 1 2
    # book_obj = models.Book.objects.filter(pk=3).first()
    # # print(book_obj.authors)  # 就相当于 已经在书籍和作者的关系表了
    # # book_obj.authors.add(1)
    # # book_obj.authors.add(2,3)
    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=2).first()
    # # book_obj.authors.add(author_obj)
    # book_obj.authors.add(author_obj,author_obj1)
    """
    add() 括号内既可以传数字也可以传数据对象
    并且都支持传多个
    """


    # 修改关系
    # book_obj = models.Book.objects.filter(pk=3).first()
    # # book_obj.authors.set([3,])
    # # book_obj.authors.set([1,3])
    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=2).first()
    # book_obj.authors.set((author_obj,))
    # book_obj.authors.set((author_obj,author_obj1))
    """
    set() 括号内 既可以传数字也传对象 
    并且也是支持传多个的
    但是需要注意 括号内必须是一个可迭代对象
    """

    #
    # book_obj = models.Book.objects.filter(pk=3).first()
    # # book_obj.authors.remove(2)
    # # book_obj.authors.remove(1,2)
    #
    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=2).first()
    # # book_obj.authors.remove(author_obj)
    # book_obj.authors.remove(author_obj,author_obj1)
    """
    remove() 括号内 既可以传数字也传对象 
    并且也是支持传多个的
    """
    # 清空
    # book_obj = models.Book.objects.filter(pk=3).first()
    # book_obj.authors.clear()
    """clear()括号内不需要传任何参数 直接清空当前书籍对象所有的记录"""


    """
    ORM跨表查询
        1.子查询
        2.连表查询
        
    正反向的概念
        外键字段在谁那儿 由谁查谁就是正向
        
        谁手里有外键字段 谁就是正向查
        没有外键字段的就是反向
        书籍对象 查  出版社    外键字段在书籍       正向查询
        出版社 查 书籍         外键字段在书籍       反向查询
        
        
        正向查询按字段
        反向查询按表名小写 ...
        
    """
    # 1.基于对象的跨表查询    子查询
    # 1.查询书籍是python入门的出版社名称
    # book_obj = models.Book.objects.filter(title='python入门').first()
    # # 正向查询按字段
    # print(book_obj.publish.name)
    # print(book_obj.publish.addr)
    # 2.查询书籍主键是6的作者姓名
    # book_obj = models.Book.objects.filter(pk=6).first()
    # # print(book_obj.authors)  # app01.Author.None
    # print(book_obj.authors.all())
    # 3.查询作者是jason的手机号
    # author_obj = models.Author.objects.filter(name='jason').first()
    # print(author_obj.author_detail.phone)
    # print(author_obj.author_detail.addr)
    """
    正向查询 按字段 
    当该字段所对应的数据有多个的时候 需要加.all()
    否者点外键字段直接就能够拿到数据对象
    """
    # 4.查询出版社是东方出版社出版过的书籍
    # publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    # # print(publish_obj.book_set)  # app01.Book.None
    # print(publish_obj.book_set.all())
    # 5.查询作者是jason写过的所有的书
    # author_obj = models.Author.objects.filter(name='jason').first()
    # # print(author_obj.book_set)  # app01.Book.None
    # print(author_obj.book_set.all())
    # 6.查询手机号是110的作者
    # author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
    # print(author_detail_obj.author)
    # print(author_detail_obj.author.name)
    # print(author_detail_obj.author.age)
    """
    反向查询按表名小写 
        什么时候需要加_set
            当查询的结果可以是多个的情况下 需要加_set.all()
        什么时候不需要加_set
            当查询的结果有且只有一个的情况下 不需要加任何东西 直接表名小写即可
    """
    # 7.查询书籍是python入门的作者的手机号
    # book_obj = models.Book.objects.filter(title='python入门').first()
    # print(book_obj.authors.all())

    # 2.基于双下划綫的跨表查询   连表查询
    """
    MySQL
        left join
        inner join
        right join
        union
    """
    # 1.查询书籍是python入门的出版社名称
    # 正向
    # res = models.Book.objects.filter(title='python入门').values('publish__name')
    # print(res)
    # 反向
    # res = models.Publish.objects.filter(book__title='python入门').values('name')
    # print(res)


    # 2.查询作者是jason的手机号码
    # 正向
    # res1 = models.Author.objects.filter(name='jason').values('author_detail__phone')
    # print(res1)
    # 反向
    # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
    # print(res)



    # 3.查询手机号是120的作者姓名

    # res2 = models.AuthorDetail.objects.filter(phone=120).values('author__name')
    # print(res2)
    # res = models.Author.objects.filter(author_detail__phone=120).values('name','author_detail__addr')
    # print(res)


    # 4.查询出版社是东方出版社出版的书籍名称
    # res = models.Publish.objects.filter(name='东方出版社').values('book__title','addr')
    # print(res)
    # 5.查询作者是jason的写过的书的名字和价格
    # res = models.Author.objects.filter(name='jason').values('book__title','book__price')
    # print(res)

    # 7.查询书籍是python入门的作者的手机号
    # res = models.Book.objects.filter(title='python入门').values('authors__author_detail__phone')
    # print(res)

 

 后记:知识梳理和相关笔记总结

表查询
    
    基于django settings源码实现自己的项目
    配置文件的可插拔式设计
        dir()
        importlib
        反射
        
    
    单表查询
        只要是queryset对象 就可以无限制的点击queryset对象的方法
        13条
            1.all()  # 查所有
            2.filter()  # 根据条件过滤 多个条件之间是and关系
            3.get()  # 直接获取数据对象  查询条件不存在直接报错
            4.first()  # 取queryset的第一个数据对象
            5.last()  # 取queryset的最后一个数据对象
            6.exclude()  # 除此之外 
            7.values()  # queryset 类似于列表套字典
            8.values_list()  # queryset 类似于列表套元组
            9.count()  # 统计数据个数
            10.distinct()  # 一定要是完全一样的数据才能去重
            11.order_by()  # 排序 默认是升序 加负号就变成降序
            12.reverse()  # 反转 排序之后才能反转
            13.exists()  # 判断queryset是否有值 结果是个布尔值
            
        神奇的双下线的查询
            price__gt
            price__lt
            price__gte
            price__lte
            price__in=[100,200,300]
            price__range=(200,800)
            title__contains  包含  模糊匹配
            title__icontains  忽略大小写
            publish_date__year  只针对年份
            publish_date__month  只针对月份
            title__startswith
            title__endswith 
            
        
    
    多表查询
        前期表准备
            图书管理系统
                一对多
                多对多
                一对一
            
        外键字段的增删改查
            一对多字段
                create(publish_id=1)
                create(publish=publish_obj)
                
                update(publish_id=2)
                update(publish=publish_obj1)
                
                models.Publish.objects.filter(pk=2).delete()
                # orm外键默认是级联更新 级联删除的
            
            多对多字段
                # 朝第三张关系表中添加数据
                book_obj.authors.add(1)
                book_obj.authors.add(1,2,3,4)
                book_obj.authors.add(author_obj)
                book_obj.authors.add(author_obj,author_obj1,author_obj2)
                # 朝第三张表修改数据
                book_obj.authors.set((1,))
                book_obj.authors.set((1,2,3))
                book_obj.authors.set((author_obj,))
                book_obj.authors.set((author_obj,author_obj1))
                # 朝第三张表删除关系
                book_obj.authors.remove(1)
                book_obj.authors.remove(1,2,3,4)
                book_obj.authors.remove(author_obj)
                book_obj.authors.remove(author_obj,author_obj1)
                # 朝第三张表清空当前书籍对象所有的记录
                book_obj.authors.clear()
                
        跨表查询
            正反向的概念:
                外键字段在谁那儿 谁就是正向
                没有外键字段的  就是反向
                
        
            口诀:
                正向查询按字段
                反向查询按表名小写
            
            
            
            基于对象  # 子查询
                """
                步骤都是先获取一个数据对象
                然后利用对象点点点的方式查到锁对应的数据
                """
                # 正向
                book_obj.publish.name
                
                book_obj.authors.all()
                
                author_obj.author_detail.addr
                """
                外键字段所对应的数据 如果是单个 不需要加all
                如果是多个 需要加all()
                """
                # 反向
                publish_obj.book_set.all()
                
                author_obj.book_set.all()
                
                author_detail_obj.author.name
                """
                反向查询 数据如果是多个
                那么需要 表名小写_set.all()
                如果是一个  直接表名小写即可
                """ 
  
            基于双下划綫  # 连表查询
                """
                left join
                right join
                inner join
                union
                """
                # 正向
                models.Book.objects.filter(title='python').values('publish__name')
                # 写外键字段publish之后 就会跨到publish表中  你想要该表的哪个字段对应的数据  就加__字段名获取
                
                models.Book.objecst.filter(pk=1).values('authors__name')
                
                models.Author.objects.filter(name='jason').values('author_detail__addr')
                
                models.Publish.objects.filter(pk=1).values('book__title')
                models.authors.objects.filter(pk=1).values('book__title')
                models.AuthorDetail.objects.filter(pk=1).values('author__name')
                
                
                # 反向
                
                models.Publish.objects.filter(book__title='python').values('name')

                
                """查询书籍id为1 的作者的 手机号"""
                models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
知识总结