zoukankan      html  css  js  c++  java
  • django之模型层

    1. ORM

    • MVC或者MTV框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动

    • ORM是“对象-关系-映射”的简称。

    Mysql

     #sql中的表                                                      
    
     #创建表:
         CREATE TABLE employee(                                     
                    id INT PRIMARY KEY auto_increment ,                    
                    name VARCHAR (20),                                      
                    gender BIT default 1,                                  
                    birthday DATE ,                                         
                    department VARCHAR (20),                                
                    salary DECIMAL (8,2) unsigned,                          
                  );
    
    
      #sql中的表纪录                                                  
    
      #添加一条表纪录:                                                          
          INSERT employee (name,gender,birthday,salary,department)            
                 VALUES   ("alex",1,"1985-12-12",8000,"保洁部");               
    
      #查询一条表纪录:                                                           
          SELECT * FROM employee WHERE age=24;                               
    
      #更新一条表纪录:                                                           
          UPDATE employee SET birthday="1989-10-24" WHERE id=1;              
    
      #删除一条表纪录:                                                          
          DELETE FROM employee WHERE name="alex"                             

    ORM

    #python的类  --->对应表
    class Employee(models.Model):
         id=models.AutoField(primary_key=True)
         name=models.CharField(max_length=32)
         gender=models.BooleanField()
         birthday=models.DateField()
         department=models.CharField(max_length=32)
         salary=models.DecimalField(max_digits=8,decimal_places=2)
    
    
     #python的类对象   --->对应记录
          #添加一条表纪录:
              emp=Employee(name="alex",gender=True,birthday="1985-12-12",epartment="保洁部")
              emp.save()
          #查询一条表纪录:
              Employee.objects.filter(age=24)
          #更新一条表纪录:
              Employee.objects.filter(id=1).update(birthday="1989-10-24")
          #删除一条表纪录:
              Employee.objects.filter(name="alex").delete()

    1 创建模型

    创建名为book的app,在book下的models.py中创建模型:

    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
         id=models.AutoField(primary_key=True)
         title=models.CharField(max_length=32)
         state=models.BooleanField()
         pub_date=models.DateField()
         price=models.DecimalField(max_digits=8,decimal_places=2)
         publish=models.CharField(max_length=32)

    2. settings配置

    若想将模型转为mysql数据库中的表,需要在settings中配置:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME':'bms',           # 要连接的数据库,连接前需要创建好
            'USER':'root',        # 连接数据库的用户名
            'PASSWORD':'',        # 连接数据库的密码
            'HOST':'127.0.0.1',       # 连接主机,默认本级
            'PORT':3306            #  端口 默认3306
        }
    }

    注意1:设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。然后,启动项目,会报错:no module named MySQLdb 。这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb 对于py3有很大问题,所以我们需要的驱动是PyMySQL 所以,我们只需要找到项目名文件下的init,在里面写入:

    import pymysql
    pymysql.install_as_MySQLdb()

    最后通过两条数据库迁移命令即可在指定的数据库中创建表 :

    python manage.py makemigrations
    python manage.py migrate

    注意2:确保配置文件中的INSTALLED_APPS中写入我们创建的app名称

    注意3:如果报错如下:

    `django.core.exceptions.ImproperlyConfigured: mysqlclient ``1.3``.``3` `or` `newer ``is` `required; you have ``0.7``.``11.None`

    MySQLclient目前只支持到python3.4,因此如果使用的更高版本的python,需要修改如下:

    通过查找路径C:ProgramsPythonPython36-32Libsite-packagesDjango-2.0-py3.6.eggdjangodbackendsmysql 这个路径里的文件把

    if version < (1, 3, 3): raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.version)

    注释掉就行了

     

    注意4:如果想打印orm转换过程中的sql,需要在settings中进行如下配置:

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

    2. ORM之单表操作

    添加表操作

    def index(request):
        # 添加表记录
    
        # 方式1:
        # book_obj = Book(title='python基础教程',price=100,pub_date='2012-12-12',publish='人民出版社')
        # book_obj.save()
    
    
        # 方式2:create的返回值就是当前生成的对象记录
        book_obj = Book.objects.create(title='django企业开发',price=100,pub_date='2018-12-12',publish='人民出版社')
        print(book_obj.title)
        print(book_obj.price)
    
        return HttpResponse('ok')

    查询表记录

    查询API

    def index(request):
        # 查询表记录
        '''
            1. 方法的返回值
            2. 方法的调用者
        '''
        # (1) all 方法:返回值:queryset对象,queryset是django自定义的一种数据类型。
        # book_list = Book.objects.all()  # [obj1,obj2......]
    
        # for obj in book_list:
        #     print(obj.title, obj.price)
    
        # print(book_list[1].title)
    
        # (2) first,last:调用者:queryset对象  返回值:model对象
        # book =  Book.objects.all().first()
        # book = Book.objects.all()[0]  # 和上面一样
    
        # (3) filter()  返回值:queryset对象
        # book_list = Book.objects.filter(price=100)  # [obj1,obj2......]
        #
        # print(book_list)  # <QuerySet [<Book: python基础教程>, <Book: django企业开发>]>
        #
        # book_obj = Book.objects.filter(price=100).first()
    
        # ret = Book.objects.first(title='go',price=100)
    
        # (4) get()  有且只有一个查询结果时,才有意义,查询出多条结果会报错。 返回值:model对象
        # book_obj = Book.objects.get(title='go')
        # print(book_obj.price)
        # book_obj = Book.objects.get(price=100)  # 报错,因为结果超过一个。price=300也报错,因为查询不到。
    
        # (5) exclude() 和filter一样,只是exclude是排除条件过滤
        # ret = Book.objects.exclude(title='go')
        # print(ret)
    
        # (6) order_by   调用者是queryset对象,返回值也是queryset对象
        # ret = Book.objects.all().order_by('-id') # 按id降序
        # ret = Book.objects.all().order_by('price','-id') # 按价格升序,价格一样的话按id降序
        # print(ret)
    
        # (7) reverse()  对查询结果反向排序
        # ret = Book.objects.all().order_by('price','-id').reverse()
        # print(ret)
    
        # (8) count()  调用者是queryset对象,返回值是int类型
        # ret = Book.objects.all().count()
        # print(ret)
    
        # (9) exists()
        # ret = Book.objects.all()
    
        # if ret:  #  如果记录很多的话就效率太低了
        #     print('ok')
    
        # ret = Book.objects.all().exists()  # 原理 LIMIT 1
        #
        # if ret:
        #     print('ok')
    
        # ========================   重要的三个方法 ========================
    
        # (10) values 调用者:queryse  返回值:queryset
        # ret = Book.objects.all()
        # for item in ret:
        #     print(item.price)
    
        # ret = Book.objects.all().values("price")
        # ret = Book.objects.values("price") # 这样也可以,本质上还是用的all,为了更好的理解,用上面的方法。
        # print(ret) # <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('100.00')}, {'price': Decimal('200.00')}]>
    
        '''
        原理:
            temp = []
            for obj in Book.objects.all():
                temp.append({
                    "price":obj.price
                })
            return temp
        '''
    
        # print(ret[0].get('price'))  # 100
    
        # ret = Book.objects.all().values("price", 'title')
        # print(ret)
        '''
        values:
        
        <QuerySet [{'price': Decimal('100.00'), 'title': 'python基础教程'},
         {'price': Decimal('100.00'), 'title': 'django企业开发'}, 
         {'price': Decimal('200.00'), 'title': 'go'}]>
        '''
    
        # (11) values_list  values里面放的是字典,values_list里面放的是元组
        # ret = Book.objects.all().values_list("price",'title')
        # print(ret)
        '''
        values_list:
        # <QuerySet [(Decimal('100.00'), 'python基础教程'),
         (Decimal('100.00'), 'django企业开发'), 
         (Decimal('200.00'), 'go')]>
        '''
    
        # (12) distinct  去重
        # ret = Book.objects.all().distinct() # 没有意义
    
        ret = Book.objects.all().values('price').distinct()
        print(ret)
    
        return HttpResponse('ok')

    基于双下划线的模糊查询

    Book.objects.filter(price__in=[100,200,300])
    Book.objects.filter(price__gt=100)
    Book.objects.filter(price__lt=100)
    Book.objects.filter(price__range=[100,200])
    Book.objects.filter(title__contains="python")   # 精确大小写
    Book.objects.filter(title__icontains="python")    # 忽略大小写
    Book.objects.filter(title__startswith="py")
    Book.objects.filter(pub_date__year=2012)
    def index(request):
        # 模糊查询
    
        # ret = Book.objects.filter(price__gt=10,price__lt=200)
        # print(ret)
    
        # ret = Book.objects.filter(title__startswith='py')
        # print(ret)
    
    
        # ret = Book.objects.filter(title__contains='g')
        # ret = Book.objects.filter(title__icontains='g')  #  不区分大小写
        # print(ret)
        #
        # ret = Book.objects.filter(price__in=[200,300])  # 区间
        # print(ret)
        
        # ret = Book.objects.filter(price__range=[100, 200]).values('title', 'price')
        # print(ret)
    
        ret = Book.objects.filter(pub_date__year=2018,pub_date__month=6)
        print(ret)
        
        
    
        return HttpResponse('ok')

    删除表记录

    def index(request):
        # 删除
        
        # 删除方法1: 调用者:queryset对象
    
        # ret = Book.objects.filter(price=100).delete()
        # print(ret)  #  (2, {'app01.Book': 2})  一般不用这个返回值
    
        # 删除方法2:调用者:model对象
        # Book.objects.filter(price=100).first().delete()
    
    
        # 修改
    
        # 调用者一定要是queryset
        Book.objects.filter(title='go').update(title='go语言')
    
    
        return HttpResponse('ok')

    3. ORM之多表操作

    一对多

    多:出版社

    一:书籍

    总结:一旦确定表关系是一对多:在多的表中创建关联字段

     

    多对多

    多:作者

    多:书籍

    总结:一旦确定表关系是多对多,要创建第三张关系表

     

    一对一

    一:作者

    一:作者详细信息

    一对第一本质上可以放到一张表里,有时候为了解耦,有时候为了查询的时候更简洁,把他们拆分成了两张表。

    一对一的关联字段必须加上唯一(Unique)这个约束,而且放到两张表里的任何一张都可以。

     

    创建模型

    from django.db import models
    
    # Create your models here.
    
    class AuthorDetail(models.Model):
        nid = models.AutoField(primary_key=True)  # 如果写了就用写的,如果不写就自动添加
        birthday = models.DateField()
        telephone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
        # 一对一
        authordetail = models.OneToOneField(to="AuthorDetail", to_field='nid', on_delete=models.CASCADE)  # 加引号会从全局去找
        '''
        翻译成:
            authordetail_id INT UNIQUE,
            FOREIGN KEY(author_detail_id) REFERENCES authordetail(id)
        '''
        
        def __str__(self):
            return self.name
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
        
        def __str__(self):
            return self.name
    
    
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        publishDate = models.DateField()
        price = models.DecimalField(max_digits=5, decimal_places=2)
    
        # 一对多
        # 关联主键可以不加to_field
        # Django会自动把publish转换成publish_id
        # null = true 允许publish_id可以为空
        publish = models.ForeignKey(to="Publish", to_field='nid', on_delete=models.CASCADE)
    
        '''
        翻译成:
            publish_id INT,
            FOREIGN KEY(publish_id) REFERENCES publish(id)
        '''
    
        # 创建多对多第一种方法
        authors = models.ManyToManyField(to='Author')
    
        '''
        翻译成:
            CREATE TABLE book_author(
                id INT PRIMARY KEY auto_increment,
                book_id INT,
                author_id INT,
                FOREIGN KEY (book_id) REFERENCES book(id),
                FOREIGN KEY (author_id) REFERENCES author(id)
            )
        '''
        
        def __str__(self):
            return self.title
    
    # 创建多对多第二种方法
    # class Book2Author(models.Model):
    #     nid = models.AutoField(primary_key=True)
    #     book = models.ForeignKey(to='Book', )  #  关联主键可以不加to_field
    #     author = models.ForeignKey(to='Author', )

    一对多添加记录

    def add(request):
        Publish.objects.create(
            name='人民出版社',
            email='123@qq.com',
            city='北京'
        )
        
         # =========================== 绑定一对多的关系  ===========================
    
        # 为book表绑定出版社
    
        # 方式一
        # book_obj = Book.objects.create(
        #     title='红楼梦',
        #     price=100,
        #     publishDate='2012-02-01',
        #     publish_id=1
        # )
        # print(book_obj.publish)  # 也能显示,与这本书籍关联的出版社对象
        # print(book_obj.publish_id)
        # print(book_obj.publish.email)
    
        # 为book表绑定关系:publish
    
        # 方式二
    
        # pub_obj = Publish.objects.filter(nid=1).first()
        # book_obj = Book.objects.create(
        #     title='水浒传',
        #     price=102,
        #     publishDate='2013-01-02',
        #     publish=pub_obj  # django会给翻译成publish_id = 1
        # )
        # print(book_obj.publish)  # 与这本书籍关联的出版社对象  # 人民出版社 #它是对象名字是__str__方法显示出来的
        # print(book_obj.publish_id)  # 也能显示  # 1
        # print(book_obj.publish.email)
    
    
        # 查询西游记的出版社对应的邮箱
    
        book_obj = Book.objects.filter(title='西游记').first()
        print(book_obj.publish.email)  # 赋值的时候给了book_obj一个publish对象
    
        return HttpResponse('ok')

    多对多添加记录

    def add(request):
        
        # =========================== 绑定多对多的关系  ===========================
    
        # book_obj = Book.objects.create(
        #     title='三国演义',
        #     price=102,
        #     publishDate='2013-01-02',
        #     publish_id=1  # django会给翻译成publish_id = 1
        # )
        # #
        # alex = Author.objects.get(name='alex')
        # egon = Author.objects.get(nid=2)
        #
        # # 绑定多对多关系的API接口 (三种方法)
        # book_obj.authors.add(alex, egon)
        # book_obj.authors.add(1, 2) # 放author的主键, 和上面的效果一样
        # book_obj.authors.add(*[1,2])   # 和上面效果一样
    
        '''
        找到book和author之间的关联表,然后在关联表里生成:
        book_id   author_id
           4          1
           4          2
        '''
    
        # 解除多对多关系
        book_obj = Book.objects.filter(nid=4).first()
        # # book_obj.authors.remove(1,2)
        # # book_obj.authors.remove(*[1,2])
        #
        # # 删除全部
        # # book_obj.authors.clear()  # 不用加任何参数,找到book_id为4的然后全部清空掉
    
    
        # all 重要
        print(book_obj.authors.all())  #  [obj1,obj2...]queryset:与这本书关联的所有作者对象集合
    
        # 查询主键为4的书籍的所有作者的名字
        ret = book_obj.authors.all().values('name') # 查询每一个作者的名字
        print(ret)
    
        return HttpResponse('ok')

    4. 跨表查询

     

    基于对象的跨表查询(翻译成子查询)

    一对多查询

    def query(request):
    
        # ----------------------  1. 基于对象的跨表查询(子查询)  ----------------------
    
        # 一对多查询
    
        '''
        select name from Publish where nid = (
        select publish_id from Book where title = '三国演义');
        
        '''
        # 一对多的正向查询:查询三国演义这本书出版社的名字
        # book_obj = Book.objects.filter(title='三国演义').first()
        # print(book_obj.publish)  # 与这本书关联的出版社对象
        # print(book_obj.publish.name)
    
    
        # 一对多的反向查询:查询人民出版社出版过的书籍名称
        publish_obj = Publish.objects.filter(name='人民出版社').first()
        print(publish_obj.book_set.all())   # queryset
    
        return HttpResponse('OK')

    多对多查询

    def query(request):
    
        # 多对多查询的正向查询:查询三国演义这本书的所有作者的名字
    
        # book_obj = Book.objects.filter(title='三国演义').first()
        # author_list = book_obj.authors.all()  # queryset
        #
        # for author in author_list:
        #     print(author.name)
    
        # 多对多查询的反向查询:查询alex出版过的所有书籍名称
        alex = Author.objects.filter(name='alex').first()
        book_list = alex.book_set.all()
        
        for book in book_list:
            print(book.title)
    
        return HttpResponse('OK')

    一对一查询

    def query(request):
        
        # 一对一查询的正向查询:查询alex的手机号
    
        # alex = Author.objects.filter(name='alex').first()
        # print(alex.authordetail.telephone)
    
        # 一对一查询的反向查询:查询手机号为110的作者的名字和年龄
        ad = AuthorDetail.objects.filter(telephone=110).first()
        print(ad.author)
        print(ad.author.age)
    
        return HttpResponse('OK')

    总结

    '''
    A-B   关联属性在A表中
    正向查询:通过A去查B。
    反向查询:通过B去查A。
    
    #  一对多查询
            正向查询:按字段
            反向查询:表名小写_set.all()
                                      book_obj.publish
            Book(关联属性:publish)    -------------->    Publish
                                       <--------------
                                      publish_obj.book_set.all()
                                      
                                      
        
        多对多查询
            正向查询:按字段
            反向查询:表名小写_set.all()
                                            author.authordetail
            Author(关联属性:authordetail)    -------------->    AuthorDetail对象
                                             <--------------
                                            authordetail.author
                                       
                                       
         一对一查询
            正向查询:按字段
            反向查询:表名小写
    '''        

    5. 基于双下划线的跨表查询(翻译成join查询)

    tip:values相当于sql里的select ,filter相当于sql里的where

    一对多

        def query(request):
            #  正向查询按字段,反向查询按表名小写,用来告诉ORM引擎join哪张表
    
            # 查询三国演义这本书出版社的名字
    
            '''
            select app01_publish.name
            from app01_book
               inner join app01_publish
                          on app01_book.publish_id = app01_publish.nid
            where app01_book.title = '三国演义'
            '''
            # 下面两种方式效率一样,建议用方式一,因为方式一比较好理解。
            
            # 方式一,正向查询(按字段)
            # ret = Book.objects.filter(title='三国演义').values("publish__name")
            # # join publish,然后要name。注意:不能写表名,要写字段的名字。
            # print(ret)  # <QuerySet [{'publish__name': '人民出版社'}]>
    
            # 方式二,反向查询(表名小写)
            ret = Publish.objects.filter(book__title='三国演义').values('name')
            # 和上一个sql语句比只是左右颠倒了,其实是完全一样的,对于ORM只是思路不同。
            # select app01_publish.name from app01_publish inner join app01_book .....
    
            print(ret) # <QuerySet [{'name': '人民出版社'}]>
    
            return HttpResponse('OK')

    多对多

      #  正向查询按字段,反向查询按表名小写,用来告诉ORM引擎join哪张表
    
        # 查询三国演义这本书的所有作者的名字
    
        '''
        select app01_author.name
        from app01_book
           inner join app01_book_authors
                      on app01_book.nid = app01_book_authors.book_id
           inner join app01_author
                      on app01_book_authors.author_id = app01_author.nid
        where app01_book.title = "三国演义"
        '''
         # 下面两种方式效率一样,建议用方式一,因为方式一比较好理解。
            
        # 方式一,正向查询(按字段)
        # 需求:通过Book表join与其关联的Author表,属于正向查询:安字段authors通知ORM引擎join book_authors与author
    
        # ret = Book.objects.filter(title='三国演义').values("authors__name")  # authors = models.ManyToManyField(to='Author')
        # print(ret) # <QuerySet [{'authors__name': 'alex'}, {'authors__name': 'egon'}]>
    
        # 方式二,反向查询(表名小写)
        # 需求:通过Author表join与其关联的Book表,属于反向查询:按表名小写book通知ORM引擎join book_authors与book
    
        ret = Author.objects.filter(book__title='三国演义').values('name')  # 和正向查询的sql语句本质一样,只是左右表的位置换了一下
        print(ret)  # <QuerySet [{'name': 'alex'}, {'name': 'egon'}]>
    
        return HttpResponse('OK')

    一对一

    def query(request):
        # 一对一查询
    
        # 查询alex的手机号
    
        # 方式一,正向查询(按字段)
        # 需求:通过Author表join与其关联的AuthorDetail表,属于正向查询:按字段authordetail通知ORM引擎join Authordetail表
        # ret = Author.objects.filter(name='alex').values('authordetail__telephone')
        # print(ret)  # <QuerySet [{'authordetail__telephone': 110}]>
    
        # 方式二,反向查询(表名小写)
        # 需求:通过Authordetail表join与其关联的Author表,属于反向查询:按表名小写author通知ORM引擎join Author表
        ret = AuthorDetail.objects.filter(author__name='alex').values('telephone')
        print(ret)  # <QuerySet [{'telephone': 110}]>
        
        return HttpResponse('OK')

    进阶练习

    def query(request):
        # 进阶练习
    
        # 查询手机号以110开头的作者出版过的所有书籍名称以及书籍出版社名称
    
        # # 方式一(正向查询):
        # # 需求:通过Book表join AuthorDetail表, Book与AuthorDetail无关联,所以需要连续跨表
        # ret = Book.objects.filter(authors__authordetail__telephone__startswith='110').values('title', 'publish__name')
        # # 这个查询语句用到了5张表,Book,Book_Authors,Author,Authordetail,Publish
        # print(ret)  # <QuerySet [{'title': '三国演义', 'publish__name': '人民出版社'}]>
    
        # 方式二(反向查询):
        ret = Author.objects.filter(authordetail__telephone__startswith=110).values('book__title', 'book__publish__name')
        print(ret)  # <QuerySet [{'book__title': '三国演义', 'book__publish__name': '人民出版社'}]>
    
        return HttpResponse('查询成功')

    6. 聚合与分组查询

    聚合查询

    def query(request):    
        # ----------------------------->聚合查询 aggregate:返回值是一个字典,不再是queryset
    
        #   查询所有书籍的平均价格
    
        '''
                select avg(price) from app01_book
            '''
    
        from django.db.models import Avg, Max, Min, Count
    
        ret =                   Book.objects.all().aggregate(avg_price=Avg('price'),max_price=Max('price'))
        print(ret)  # {'avg_price': 101.5, 'max_price': Decimal('102')}
    
        return HttpResponse('查询成功')

    单表分组查询

    # model.py
    class Emp(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        salary = models.DecimalField(max_digits=8, decimal_places=2)
        dep = models.CharField(max_length=32)
        province = models.CharField(max_length=32)
    
    
    # views.py
    def query(request):
        # ----------------------------->分组查询 annotate,返回值仍然是queryset
    
        # =====  单表分组查询:=====
    
        # 示例1
    
        # 查询每一个部门的名称以及员工的平均薪水
    
        from django.db.models import Avg, Max, Min, Count
    
        '''
            select dep,avg(salary) from emp group by dep 
        '''
    
        # ret = Emp.objects.values('dep').annotate(avg_salar=Avg('salary'))
        # print(ret)  # <QuerySet [{'dep': '保安部', 'avg_salar': 5000.0}, {'dep': '教学部', 'avg_salar': 6000.0}]>
        #
        # # 单表分组查询的ORM语法:单表模型.objects.values('group by的字段').annotate(聚合函数("统计字段"))   # values里的是select的字段
    
        # 查询每一个省份的名称以及对应的员工数
    
        # ret = Emp.objects.values('province').annotate(emp_count=Count('id'))
        # print(ret)  # <QuerySet [{'province': '山东省', 'emp_count': 2}, {'province': '河北省', 'emp_count': 1}]>
    
    
        # 补充知识点:
        ret = Emp.objects.all()
        print(ret)  # select * from emp
    
        ret = Emp.objects.values('name')  # 和ret = Emp.objects.all().values('name')语法相同
        print(ret)  # select name from emp
    
        # 在单表下,这样按照group by分组是没有任何意义的。
    
    
        return HttpResponse('查询成功')

    多表分组查询

    示例1:查询每一个出版社的名称以及出版的书籍个数

      def query(request):
        # 查询每一个出版社出版的书籍个数  -->  不需要跨表
        # Book.objects.values('publish_id').annotate(Count('id'))
    
        # 查询每一个出版社的名称以及出版的书籍个数   -->  需要跨表
    
        # 方式1(只显示id):
        '''
        SELECT "app01_publish"."nid", COUNT("app01_book"."nid") AS "count_book"
        FROM "app01_publish"
               LEFT OUTER JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id")
        GROUP BY "app01_publish"."nid"
        LIMIT 21;
        '''
        # ret = Publish.objects.values("nid").annotate(count_book=Count('book__nid'))
        # print(ret)  # <QuerySet [{'nid': 1, 'count_book': 3}, {'nid': 2, 'count_book': 1}]>
    
        # 方式2:
        '''
        SELECT "app01_publish"."name", COUNT("app01_book"."nid") AS "count_book"
        FROM "app01_publish"
           LEFT OUTER JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id")
        GROUP BY "app01_publish"."name"
        LIMIT 21;
        '''
        # ret = Publish.objects.values("name").annotate(count_book=Count('book__nid'))
        # print(ret)  # <QuerySet [{'name': '人民出版社', 'count_book': 3}, {'name': '河北出版社', 'count_book': 1}]>
    
        # 方式3:建议用这种方式,以表的主键作为分组条件:
        '''
        
        SELECT "app01_publish"."name", COUNT("app01_book"."nid") AS "count_book"
        FROM "app01_publish"
           LEFT OUTER JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id")
        GROUP BY "app01_publish"."nid", "app01_publish"."name"
        LIMIT 21;
        '''
        ret = Publish.objects.values("nid").annotate(count_book=Count('book__nid')).values('name', 'count_book')
        print(ret)  # <QuerySet [{'name': '人民出版社', 'count_book': 3}, {'name': '河北出版社', 'count_book': 1}]>
        
        # 第三种方法取的是nid,但是却能取出name,原因是ret是一个queryset对象,它储存了Publish的所有字段外加count_book
        
        # 按照Publish下的每一个字段进行 group by
        ret = Publish.objects.all().annotate(count_book=Count('book__nid'))
        print(ret) # 两个publish对象 <QuerySet [<Publish: 人民出版社>, <Publish: 河北出版社>]>

    示例2:查询每一个作者的名字以及出版过的书籍的最高价格

    def query(request):
        from django.db.models import Avg, Max, Min, Count
        '''
        select app01_author.name,max(app01_book.price) as highest_price
        from app01_book
           inner join app01_book_authors on app01_book.nid = app01_book_authors.book_id
           inner join app01_author on app01_book_authors.author_id = app01_author.nid
        group by app01_author.nid
        '''
    
        ret = Author.objects.values('pk').annotate(max_price = Max('book__price')).values('name','max_price')
        # ret = Publish.objects.all().annotate(count_book=Count('book__nid')) # 和上面效果一样
        print(ret)  #  <QuerySet [{'name': 'alex', 'max_price': Decimal('102')}, {'name': 'egon', 'max_price': Decimal('102')}]>
    
        # 跨表的分组查询的模型
        # 每一个的表模型.objects.values('pk').annotate(聚合函数(关联表__统计字段))
        return HttpResponse('查询成功')

    示例3:查询每一个书籍的名称,以及对应的作者个数

     def query(request):
        ret = Book.objects.values('pk').annotate(author_count=Count('authors__name')).values('title','author_count')
        print(ret) # <QuerySet [{'title': '红楼梦', 'author_count': 0}, {'title': '西游记', 'author_count': 0}, {'title': '水浒传', 'author_count': 0}, {'title': '三国演义', 'author_count': 2}]>
    
        return HttpResponse('查询成功')

    总结

    '''
    每一个的表模型.objects.values('pk').annotate(聚合函数(关联表__统计字段)).values('表模型的所有字段以及统计字段')
    
    每一个的表模型.objects.annotate(聚合函数(关联表__统计字段)).values('表模型的所有字段以及统计字段')  
    
    每一个的表模型.objects.all().annotate(聚合函数(关联表__统计字段)).values('表模型的所有字段以及统计字段')  
    '''

    练习

    def query(request):
        # 练习
        # 统计每一本以三开头的书籍的作者个数:
    
        # ret = Book.objects.filter(title__startswith='三').values('pk').annotate(author_count=Count('authors__name')).values(
        #     'title', 'author_count')
        # print(ret) # <QuerySet [{'title': '三国演义', 'author_count': 2}]>
    
        # 统计不止一个作者的图书:
    
        ret = Book.objects.values('pk').annotate(author_count=Count('authors__nid')).filter(author_count__gt=1).values(
            'title', 'author_count')
        print(ret)  # <QuerySet [{'title': '三国演义', 'author_count': 2}]>   原生sql用了having
    
        '''
        SELECT "app01_book"."title", COUNT("app01_book_authors"."author_id") AS "author_count"
        FROM "app01_book"
            LEFT OUTER JOIN "app01_book_authors" ON ("app01_book"."nid" = "app01_book_authors"."book_id")
        GROUP BY "app01_book"."nid", "app01_book"."title"
        HAVING COUNT("app01_book_authors"."author_id") > 1
        LIMIT 21;
        '''
        return HttpResponse('查询成功')

    7. F查询和Q查询

    补充

    # modles.py
    # 在book表新加两个字段
    
    read_number = models.IntegerField()
    comment_number = models.IntegerField()
        
    # 在makemigrations的时候提示:
    '''
     1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
     2) Quit, and let me add a default in models.py
    '''
    # 这是因为已有的数据没有设置这俩值,给他们换一个default值就好了
    read_number = models.IntegerField(default=0)
    comment_number = models.IntegerField(default=0)

    F查询

    def query(request):
        # F查询可以对两个字段的值做比较用
    
        from django.db.models import F, Q
    
        # 查询评论数大于阅读数的书籍
        # ret = Book.objects.filter(comment_number__gt=F('read_number'))
        # print(ret)  # <QuerySet [<Book: 西游记>, <Book: 三国演义>]>
    
        # F查询支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作
    
        # 给每一个书籍的价格加10
        Book.objects.all().update(price=F('price') + 10)
        
        return HttpResponse('查询成功')

    Q查询

    def query(request):
        # filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象。
    
        # 你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT)
    
        # 查询名字等于红楼梦而且价格等于101的书籍
        # ret = Book.objects.filter(title='红楼梦', price=110)
        # ret = Book.objects.filter(Q(title='红楼梦') & Q(price=110))
    
        # 查询名字等于红楼梦或价格等于101的书籍
        # ret = Book.objects.filter(Q(title='红楼梦') | Q(price=110))
    
        # 查询名字不等于红楼梦或者价格等于101的书籍,但是评论数要大于100。
        ret = Book.objects.filter(~Q(title='红楼梦') | Q(price=110),comment_number__gt=100) # 必须Q在前面,自己的键值对在后面
        print(ret)  # <QuerySet [<Book: 红楼梦>, <Book: 西游记>, <Book: 水浒传>, <Book: 三国演义>]>
    
        return HttpResponse('查询成功')

     

  • 相关阅读:
    机器学习西瓜书笔记---1、绪论
    机器学习西瓜书白话解读笔记---0101-0102、绪论基本概念
    机器学习西瓜书白话解读笔记---0000、资料相关
    心得体悟帖---201123(游戏心得)
    PCA数学原理
    如何通俗易懂地解释卷积
    git操作中出现Unlink of file '......' failed. Should I try again?
    checker jenkins 启动配置
    Linux下Shell脚本运行程序不输出日志到终端
    Spring boot 配置文件位置
  • 原文地址:https://www.cnblogs.com/lshedward/p/10351821.html
Copyright © 2011-2022 走看看