zoukankan      html  css  js  c++  java
  • Django -ORM

    单表操作

    添加记录

    1     方法一: 实例化Book类 进行添加记录
    2 
    3     book_obj = Book(id=1,title='python',price=101,pub_date='2014-02-13',publish="华夏出版社")
    4     book_obj.save()    # 此方法添加之后必须有 save 操作 ,否则数据不会增加
    5 
    6     方法二: 使用Book的 object管理器的create方法添加记录
    7     obj = Book.objects.create(title='C++',price=89,pub_date='2014-12-03',publish='海浪出版社')
    8     print(obj.title )
    
    

    查询表记录API

    (1). all()方法:查询所有数据  返回一个Queryset对象

    (2).first() 和 last()方法: 返回第一个和最后一个对象 返回值:models对象 调用者: Queryset
    (3). filter(**kwargs):返回和筛选条件相匹配的对象 调用者:object管理器  返回值:Queryset对象
    (4).get(**kwargs)方法: 返回与所给筛选条件相匹配的model对象  调用者:object管理器  返回值:model对象
    (5). exclude(**kwargs)方法:排除符合条件的数据  调用者:Queryset对象  返回值:Queryset对象
    (6). order_by(**kwargs)方法:根据条件进行排序  调用者:Queryset对象  返回值:Queryset对象
    (7).count()方法:对数据计数(可加约束)  调用者:object管理器  返回值:int数值
    (8).exist()方法:判断数据是否为空  调用者:Queryset对象  返回值:bool类型
    (9).value()方法:通过内循环获取对应字段的数据 调用者:object管理器或者Queryset对象 返回值:Queryset对象(其中数据以字典的形式存储)
    (10).value_list()方法:通过内循环获取对应字段的数据  调用者:object管理器或者Queryset对象  返回值:Queryset对象(其中数据以元组的形式存储)
    (11).distinct()方法:对于数据中的某一字段进行去重  调用者:Queryset对象  返回值:Queryset对象(其中数据以字典的形式存储)
     1 obj = Book.objects.all()
     2 print(obj)   # 返回Queryset列表对象 :[obj1,obj2,obj3,....]
     3 print(type(obj))
     4 
     5  for i in obj:
     6      print(i.title)
     7 
     8 '''
     9 遍历书名:
    10     python
    11     java
    12     lua
    13     lua
    14     lua
    15     C++
    16 '''
    17 print(obj[0].title,obj[1].title)   # python java
    all()方法:查询所有数据 返回一个Queryset
     first_obj = Book.objects.all().first()
     last_obj = Book.objects.all().last()
     print(first_obj,last_obj)   # Book object (1) Book object (6)
    # 相当于
    first_obj = Book.objects.all()[0]
    print(first_obj)   # Book object (1)
    first() 和 last()方法: 返回第一个和最后一个对象 返回值:models对象 调用者: Queryset
     book_list = Book.objects.filter(publish='海龟出版社')
    print(book_list)   # <QuerySet [<Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>]>
    fir_obj = Book.objects.filter(publish='海龟出版社').first()  # Book object (2)
    last_obj = Book.objects.filter(publish='海龟出版社').last()  # Book object (5)
    filter(**kwargs):返回和筛选条件相匹配的对象 调用者:object管理器 返回值:Queryset对象
    # 只有结果为一时才有效  查询结果为空或者为多者时都会报错
    
     obj = Book.objects.get(title='python')   # model对象 :Book object (1)
     print(obj.title)  # python
    # obj = Book.objects.get(title='lua')  # 查询结果为多者报错:get() returned more than one Book -- it returned 3!
    get(**kwargs)方法: 返回与所给筛选条件相匹配的model对象 调用者:object管理器 返回值:model对象
    book_list  = Book.objects.all().exclude(title='python')  # 单条件排除
    book_list=Book.objects.all().exclude(title='C++',publish="海浪出版社")  # 多条件排除
    # for book in  book_list:
    #     print(book.publish)
    exclude(**kwargs)方法:排除符合条件的数据 调用者:Queryset对象 返回值:Queryset对象
    obj = Book.objects.all().order_by("title")  # 单条件排序
    
    obj2 = Book.objects.all().order_by("title","price")  # 多条件排序
    order_by(**kwargs)方法:根据条件进行排序 调用者:Queryset对象 返回值:Queryset对象
    res = Book.objects.all().count()
    print(res,{"type":type(res)})      # 6 {'type': <class 'int'>}
    count()方法:对数据计数(可加约束) 调用者:object管理器 返回值:int数值
     ret  = Book.objects.all().exists()
    print(ret,{"type":type(ret)})       # True {'type': <class 'bool'>}
    exist()方法:判断数据是否为空 调用者:Queryset对象 返回值:bool类型
     ret1 = Book.objects.all().values("title")    #  等于 ret1 = Book.objects.values("title")
    ret2 = Book.objects.all().values("title",'price')
    
    print(ret1,{"type":type(ret1)})
    # # <QuerySet [{'title': 'python'}, {'title': 'java'}, {'title': 'lua'}, {'title': 'Go'}, {'title': 'C#'}, {'title': 'C++'}]> {'type': <class 'django.db.models.query.QuerySet'>}
    print(ret2,{"type":type(ret2)})
    # <QuerySet [{'title': 'python', 'price': Decimal('101.00')}, {'title': 'java', 'price': Decimal('100.00')}, {'title': 'lua', 'price': Decimal('99.00')}, {'title': 'Go', 'price': Decimal('68.00')}, {'title': 'C#', 'price': Decimal('70.00')}, {'title': 'C++', 'price': Decimal('89.00')}]> {'type': <class 'django.db.models.query.QuerySet'>}
    value()方法:通过内循环获取对应字段的数据 调用者:object管理器或者Queryset对象 返回值:Queryset对象(其中数据以字典的形式存储)
     ret1 = Book.objects.all().values_list("title")
     # ret1 = Book.objects.values("title")  # 同上
    ret2 = Book.objects.all().values_list("title", 'price')
    #
    print(ret1, {"type": type(ret1)})
     # <QuerySet [('python',), ('java',), ('lua',), ('Go',), ('C#',), ('C++',)]> {'type': <class 'django.db.models.query.QuerySet'>}
    print(ret2, {"type": type(ret2)})
    # <QuerySet [('python', Decimal('101.00')), ('java', Decimal('100.00')), ('lua', Decimal('99.00')), ('Go', Decimal('68.00')), ('C#', Decimal('70.00')), ('C++', Decimal('89.00'))]> {'type': <class 'django.db.models.query.QuerySet'>}
    value_list()方法:通过内循环获取对应字段的数据 调用者:object管理器或者Queryset对象 返回值:Queryset对象(其中数据以元组的形式存储)
     ret = Book.objects.all()
     print(ret)
     ret1 = Book.objects.values('price')
     print(ret1)
     ret2 = Book.objects.values('price').distinct()
     print(ret2)
    '''
    结果:
    ret: <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>, <Book: Book object (6)>]>
    
    ret1: <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('100.00')}, {'price': Decimal('99.00')}, {'price': Decimal('68.00')}, {'price': Decimal('70.00')}, {'price': Decimal('89.00')}]>
    
    ret2: <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('99.00')}, {'price': Decimal('68.00')}, {'price': Decimal('70.00')}, {'price': Decimal('89.00')}]>
    
    '''
    distinct()方法:对于数据中的某一字段进行去重 调用者:Queryset对象 返回值:Queryset对象(其中数据以字典的形式存储)
     

    ========================= 单表查询之模糊查询 =========================
    数值方面模糊查询

    (1). price__lt 查询价格小于80的数据
     ret1 = Book.objects.filter(price__lt=80)
     print(ret1)    # <QuerySet [<Book: Book object (4)>, <Book: Book object (5)>]>
    (2). price__gt 查询价格大于70的数据
     ret2 = Book.objects.filter(price__gt=70)
     print(ret2)   # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (5)>, <Book: Book object (6)>]>
    (3).查询价格大于70且价格小于80的数据
     ret3 = Book.objects.filter(price__gt=70,price__lt=80,)
     print(ret3)   # <QuerySet [<Book: Book object (5)>]>
    (4).查询价格为列表中的数据
     ret4 = Book.objects.filter(price__in=[100,200])
     print(ret4)  # <QuerySet [<Book: Book object (1)>]>

    ======== 内容方面模糊查询

    ===包含方面查询:
    (1).查询title字段包含小写字母”o“的数据 区分大小写
     ret1 = Book.objects.filter(title__contains="o")
     print(ret1)  # <QuerySet [<Book: Book object (5)>, <Book: Book object (6)>]>
    # 查询title字段包含小写字母”O“的数据
    ret2 = Book.objects.filter(title__contains="O")
    print(ret2)   # <QuerySet []>  # 没有数据显示为空

    (2).不区分大小写查询
     ret = Book.objects.filter(title__icontains="O")
     print(ret)  # <QuerySet []>

    ===开头结尾查询:

    1、查询以”C“为开头的数据 区分大小写
     ret1 = Book.objects.filter(title__startswith='C')
     print(ret1)  # <QuerySet [<Book: Book object (5)>, <Book: Book object (6)>]>

    2、查询以”c“为开头的数据 区分大小写
     ret1 = Book.objects.filter(title__startswith='c')
     print(ret1)   # <QuerySet []>

    3、查询以”c“为开头的数据 不区分大小写
     ret1 = Book.objects.filter(title__istartswith='c')
     print(ret1)  # <QuerySet [<Book: Book object (5)>, <Book: Book object (6)>]>

    4、查询以”n“为结尾的数据 区分大小写
     ret1 = Book.objects.filter(title__endswith='n')
     print(ret1)  # <QuerySet [<Book: Book object (1)>]>

    5、查询以”N“为结尾的数据 区分大小写
     ret1 = Book.objects.filter(title__endswith='N') 
     print(ret1)  # <QuerySet []>

    6、查询以”N“为结尾的数据 不区分大小写
     ret1 = Book.objects.filter(title__iendswith='N')
     print(ret1)  # <QuerySet [<Book: Book object (1)>]>


    ========== 日期方面查询

    1、 查询年份为2014
    ret1 = Book.objects.filter(pub_date__year=2014,)
    print(ret1)  # <QuerySet [<Book: Book object (1)>, <Book: Book object (6)>]>
    2、 查询年份为2014 月份为12
    ret2=Book.objects.filter(pub_date__year=2014,pub_date__month=12)
    print(ret2)   # <QuerySet [<Book: Book object (6)>]>
    3、 查询年份为2014 月份为12 天数为3的数据
    ret3 = Book.objects.filter(pub_date__year=2014,pub_date__month=12,pub_date__day=3)
    print(ret3)   # <QuerySet [<Book: Book object (6)>]>

    删除记录和修改记录

    1、 删除:delete()方法   调用者:Queryset对象 和 model对象
     ret = Book.objects.filter(title="C++").delete()   # Queryset对象调用
     print(ret)   #  (1, {'app01.Book': 1})
    
     ret1 = Book.objects.filter(publish="海洋出版社").first().delete()   # Queryset对象调用
     print(ret1)   #  (1, {'app01.Book': 1})

    2、 修改记录:update()方法 调用者: Queryset对象
    ret = Book.objects.filter(title="C#").update(price=99)# print(ret)   # 2

    多表操作

    数据库关系:

    • 一对一
    • 一对多
    • 多对多

    一、创建模型

    实例:我们来假定下面这些概念,字段和关系
    作者模型:一个作者有姓名和年龄。
    作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
    出版商模型:出版商有名称,所在城市以及email。
    书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
    模型建立如下:

    class Publish(models.Model):
        '''
        出版社信息表
        '''
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        tel =  models.IntegerField()
        email = models.EmailField()
    
    
    class Book(models.Model):
        '''
        书籍表
        '''
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        price = models.DecimalField(decimal_places=2,max_digits=8)
        pub_date = models.DateField()
        # 与Publish表建立一对多的关系 外键建立在多的一方:ForeignKey(to="关系表",to_field="关联字段",on_delete=models.CASCADE)
        publish = models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
        # 与Author表建立多对多的关系 ManyToManyField(to="关系表",)
        authors = models.ManyToManyField(to="Author",)
    
    
    
    class AuthorDetail(models.Model):
        '''
        作者详情表
        '''
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        email = models.EmailField(max_length=32)
        addr = models.CharField(max_length=32)
    
    class Author(models.Model):
        '''
        作者表
        '''
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        # 与作者详情表为一对一关系  使用OneToOneField(to="关系表",to_field="关联字段",on_delete=models.CASCADE)
        #  在django 2.0 以上版本 需要加上 on_delete=models.CASCADE
        #  不然会报错 ”TypeError: __init__() missing 1 required positional argument: 'on_delete'“
        authordetail = models.OneToOneField(to="AuthorDetail",to_field="nid" ,on_delete=models.CASCADE)    #  在django 2.0 以上版本 需要加上 on_delete=models.CASCADE
    注意:
    在django 2.0 以上版本 需要加上 “ on_delete=models.CASCADE ”,
    不然会报错 ”TypeError: __init__() missing 1 required positional argument: 'on_delete'
    
    

    执行命令后生产表如下:

        

     其中表“app01_book_authors” 是ORM根据models中的关联关系生成的,不是我们手动创建的 

        # 与Author表建立多对多的关系 ManyToManyField(to="关系表",)
        authors = models.ManyToManyField(to="Author",)

    注意事项:

    • 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  
    • id 字段是自动添加的
    • 对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
    • 这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
    • 定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
    • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None

    一、添加记录:

    (1)一对一添加

        # 添加出版社信息(单表)
        pub = Publish.objects.create(nid=1,name="人民出版社",city="北京",tel=1234456,email="12156@qq.com")
        pub = Publish.objects.create(name="海南出版社",city="海南",tel=1232316,email="2421356@qq.com")

    数据库数据:

        

    (2)一对多添加

    往书籍Book表中添加数据,并关联出版社Publish表

        #  方式一
        # book_obj = Book.objects.create(nid=2,title="java",price=480,pub_date="2018-05-06",publish_id=1)
        # print(book_obj.title)
        # print(book_obj.price)
        # print(book_obj.publish)
        # print(book_obj.publish.city)
        # print(book_obj.publish.email)
        # print(book_obj.publish.tel)
        # print(book_obj.publish.tel)
        # print(book_obj.publish_id)
    
        # 方式二
        # 先取出一个Publish对象pub_obj 然后让publish=pub_obj  Django会根据book表里的publish关系获取到对应的出版社id 然后进行关联
        # pub_obj = Publish.objects.filter(nid=1).first()
        # book_obj = Book.objects.create(title="lua",price=12312,pub_date="2011-02-16",publish=pub_obj)
        #
        # print(book_obj.publish)       # Publish object (1)
        # print(book_obj.publish.city)  # 北京
        # print(book_obj.publish.email) # 12156@qq.com
        # print(book_obj.publish.tel)   # 1234456
        # print(book_obj.publish_id)    # 1

     数据库数据:表app01_book

        

    (3)多对多添加

    现在往作者表:Author、作者详情表AuthDetail中添加数据,并进行关联

        # 创建作者信息
        AuthorDetail.objects.create(email="123123@qq.com",addr="sdfasdf")
        AuthorDetail.objects.create(email="421233@qq.com",addr="gesdf")
        AuthorDetail.objects.create(email="23145@qq.com",addr="hainan")
        AuthorDetail.objects.create(email="34212@qq.com",addr="beijing")
    
        Author.objects.create(name="Tom",authordetail_id=1)
        Author.objects.create(name="Jane",authordetail_id=2)
        Author.objects.create(name="Tone",authordetail_id=3)
        Author.objects.create(name="Jin",authordetail_id=4)
    
        # 给python关联作者
        book1 = Book.objects.get(title='python')
        book2 = Book.objects.get(title='java')
    
        book1.authors.add(1)
        book1.authors.add(2)
        # 上面两步等同于
        # book1.authors.add(*[1,2])
    
        book2.authors.add(2,3)
    
        # 解决关联信息
    
        book1.authors.remove(1)  # 单条解除
        book1.authors.clear()  # 全部解除
        print(book2.authors.all())  # <QuerySet [<Author: Tom>, <Author: Jin>]>

    表app01_author:

        

    表app01_authordetail :

         

    表app01_book_authors :

    二、查询记录:

    =========================基于对象的跨表查询===========================

    正反向查询:

        '''
        查询分为正向和反向查询 比如表A和表B 关联属性在A中
        
                  根据字段进行查询:obj.关联属性
        正向查询: A----------------------->B
                    
                    
                根据表名进行查询:obj.表名小写_set.all()
        反向查询: B------------------------>A
                  
        '''

    一对多查询

        '''
        一对多:
        正向查询: Book--------------->Publish
                    book_obj.publish
    
    
        反向查询: Publish --------------->Book
                    pub_obj.book_set
        '''
        # 表Book和表Publish(一对多)  关联属性publish在Book中
        # 查询书名python的出版社名字(正向查询)
    
        book = Book.objects.filter(title='python').first()  # 获取Book对应的对象
        print(book.publish.name)  # 人民出版社
    
        # 查询人民出版社的出版的所有书籍名字(反向查询)
    
        pub_obj = Publish.objects.filter(name="人民出版社").first()  # 获取Publish对应的对象
        ret = pub_obj.book_set.all()    # 获取对应的书籍
        print(ret)   # <QuerySet [<Book: python>, <Book: java>, <Book: go>, <Book: lua>]>

    多对多查询

        '''
        多对多:
        正向查询: Book--------------->Author
                    book_obj.authors
    
        反向查询: Author --------------->Book
                    author_obj.book_set.all()
        '''
        #  查询书籍python的所有作者名字(正向查询)
    
        book_obj = Book.objects.filter(title="python").first()
        ret = book_obj.authors.all()
        print(ret)   # <QuerySet [<Author: Tom>, <Author: Jane>]>
    
         # 查询书籍Tom的所有书籍名字(反向查询)
        author_obj = Author.objects.filter(name="Tom").first()
        ret =   author_obj.book_set.all()
        print(ret)   # <QuerySet [<Book: java>, <Book: python>]>

    一对一查询

        '''
        一对一: 因为是一对一关系 所以查询结果是唯一的  
        正向查询: Author--------------->Authordetail
                    book_obj.authordetail
    
        反向查询: Authordetail --------------->Author
                    authordetail_obj.author
        '''
        # 查询Tom的地址
        author_obj = Author.objects.filter(name="Tom").first()
        print(author_obj.authordetail.addr)  # sdfasdf
    
        # 查询邮箱为23145@qq.com的姓名和年龄
        authordetail_obj = AuthorDetail.objects.filter(email="23145@qq.com").first()
        print(authordetail_obj.author.name)   # Tone

    =========================基于双下滑线的模糊查询 ========================

    查询方式:

    '''
    正向查询用字段 反向查询用 "表名小写__属性“ 从而告诉ORM引擎 join 哪张表
    '''
    一对多: 
    查询书名为python的出版社名字
    '''
    sql语句查询:
        select app01_publish.name from app01_book  inner join app01_publish  on
    app01_book.title="python" and app01_book.nid = app01_publish.nid;
    
    '''
    
    
    方式1 通过Book表join与其关联的Publish表,属于正向查询;再按照字段 publish 告知ORM join Publish表
    ret1 = Book.objects.filter(title="python").values("publish__name")
    print(ret1)  # <QuerySet [{'publish__name': '人民出版社'}]>

    方式二:通过Publish表join与其关联的Book表,属于反向查询;再按照表名小写 book__title 告知ORM引擎 join Book表
    ret2 = Publish.objects.filter(book__title="python").values("name")
    print(ret2)  #  <QuerySet [{'name': '人民出版社'}]>

    两种方式的sql语句:

        方式1 打印的sql语句:
        (0.001) SELECT "app01_publish"."name" FROM "app01_book" INNER JOIN "app01_publish" ON 
        ("app01_book"."publish_id" = "app01_publish"."nid") WHERE "app01_book"."title" = 'python' LIMIT 21; args=('python',)
        
        方式2 打印的sql语句:
        (0.000) SELECT "app01_publish"."name" FROM "app01_publish" INNER JOIN "app01_book" ON
         ("app01_publish"."nid" = "app01_book"."publish_id") WHERE "app01_book"."title" = 'python' LIMIT 21; args=('python',)

    从sql语句可以看出 ,两种方式的sql语句都是一样的  只不过顺序颠倒了下

     多对多:

    现在用双下划线查询上面的例子:

        #  查询书籍python的所有作者名字(正向查询)
        # 方式一:通过Book表join与其关联的Author表 属于正向查询;再通过字段”authors“告知ORM join Author表
    
        ret = Book.objects.filter(title="python").values("authors__name")
        print(ret)   # <QuerySet [{'authors__name': 'Tom'}, {'authors__name': 'Jane'}]>
    
        # 方式二:通过Author表join与其关联的Book表,属于反向查询;按表名小写book告知ORM引擎join book_authors表
    
        ret = Author.objects.filter(book__title="python").values("name")
        print(ret) # <QuerySet [{'name': 'Tom'}, {'name': 'Jane'}]>

    一对一

        # 查询Jane的addr
        # 方式一:通过Author表join与其关联的Authordetail表 属于正向查询;再按照字段authordetail 告知ORM join Authordetail表表
        ret = Author.objects.filter(name="Jane").values("authordetail__addr")
        print(ret)  # <QuerySet [{'authordetail__addr': 'gesdf'}]>
    
        # 方式一:通过Authordetail表join与其关联的Author表 属于反向查询;再按照表明小写“author 告知ORM join Author表
        ret = AuthorDetail.objects.filter(author__name="Jane").values("addr")
        print(ret)  # <QuerySet [{'addr': 'gesdf'}]>

    连续跨表查询

    查询地址以“h”开头的所有作者出版的 书籍以及出版社名称

    方式一:

        '''
        拆分:以作者为根 查询对应的书籍名称以及其出版社名称
            查询地址以“h”开头的所有作者  
            出版的书籍以及出版社名称
            
        涉及的表 :Author,AuthorDetail,Book,Publish
        Author与AuthorDetail有关联 且属于正向查询 所以使用字段 authordetail 找出对应的作者 --> Author.objects.filter(authordetail__addr__startswith="h")
        Author与Book有关联,且属于反向查询,所以使用小写表名获取书籍名称 --> values("book__title")
        Author和Publish没有关联,所以需要使用连续跨表查询  values("book__publish__name")
        '''
        ret = Author.objects.filter(authordetail__addr__startswith="h").values("book__title","book__publish__name")
        print(ret)   # <QuerySet [{'book__title': 'java', 'book__publish__name': '人民出版社'}]>

    方式二:

        '''
        拆分:以书籍为根 查询关系:Book --> Author --> AuthorDetail --> Publish
            查询地址以“h”开头的所有作者出版的书籍
            以及出版社名称
        
        涉及的表 :Author,AuthorDetail,Book,Publish
        Book与AuthorDetail没有关联 所以需要使用连续跨表查询 --> Book.objects.filter(authors__authordetail__addr__startswith="h")
        Book与Publish有关联,且属于正向查询 所以使用字段 publish 获取出版社名字-> values('title',"publish__name")
        '''
      ret = Book.objects.filter(authors__authordetail__addr__startswith="h").values('title',"publish__name")
        print(ret)  # <QuerySet [{'title': 'java', 'publish__name': '人民出版社'}]>

    聚合查询

    aggregate():聚合管理器, 需配合聚合函数使用 (Avg,Max,Min,Count,..)

    注意:aggregate() 返回的是一个字典 不再是Queryset集合

    示例:

        from django.db.models import Avg,Max,Min,Count  # 导入聚合函数
        ret = Book.objects.all().aggregate(Avg("price"))
        print(ret)   # {'price__avg': Decimal('3335.5')}  price__avg是ORM根据聚合函数和属性以双下划线拼成的,也可以自定义键名
        ret = Book.objects.all().aggregate(avg_price=Avg("price"))
        print(ret)  # {'avg_price': Decimal('3335.5')}
    
        ret = Book.objects.all().aggregate(Max("price"),Min("price"),Count("price"))    # 获取最高价格和最低价格 书籍数量
        print(ret)   # {'price__max': Decimal('12312'), 'price__min': Decimal('100'), 'price__count': 4}

    分组查询

    单表分组查询:

    先创建一个员工表:

    class Empers(models.Model):
        '''
        员工信息详情表
        '''
        nid = models.AutoField(primary_key=True)
        department = models.CharField(max_length=32)
        name = models.CharField(max_length=32)
        email = models.EmailField(max_length=32)
        salary = models.IntegerField()
        provience = models.CharField(max_length=32)

    添加数据:

        Empers.objects.create(name="join",email="sdsfs21@qq.com",salary="5333",department="开发部",provience="北京")
        Empers.objects.create(name="tom",email="52342s21@qq.com",salary="5377",department="开发部",provience="上海")
        Empers.objects.create(name="jane",email="21321@qq.com",salary="6000",department="销售部",provience="天津")
        Empers.objects.create(name="爱尔兰新",email="efas21@qq.com",salary="12000",department="后勤部",provience="北京")

    查询示例:

        # 查询所有部门及其员工的平均薪资
    
        ret = Empers.objects.values("department").annotate(Avg("salary"))
        print(ret) # <QuerySet [{'department': '后勤部', 'salary__avg': 12000.0}, {'department': '开发部', 'salary__avg': 5355.0}, {'department': '销售部', 'salary__avg': 6000.0}]>
    
        # 查询所有省份及其员工的人数
    
        ret = Empers.objects.values("provience").annotate(Count("name"))
        print(ret)  # <QuerySet [{'provience': '上海', 'name__count': 1}, {'provience': '北京', 'name__count': 2}, {'provience': '天津', 'name__count': 1}]>
    

    总结:

     ORM语法:单表模型.objects.values("group by的字段").annotate(聚合函数(“字段”))

    单表模型.objects.values("group by的字段") 相当于 sql语句的:“select * from 表名 group by 字段”

    注意:

    在单表查询中annotate是以前面的字段进行分组统计的,如果分组的字段包含主键,因为主键是唯一的,所以分组就是没有意义的

    多表分组查询:

    示例1:

        '''
        
        Book 表:
        nid title   pub_date    publish_id     price
        1    python    2018-05-06      1            100
        2    java    2018-05-06        1            480
        3    go        2018-08-26        1            450
        4    lua        2011-02-16      1            12312
    
        Publish 表:
        nid     name    city   tel              email
        1    人民出版社    北京        1234456        12156@qq.com
        14    海南出版社    海南        1232316        2421356@qq.com
        15    天津出版社    天津        2311312        34221356@qq.com
        
        # 查询所有书籍及其出版社的名字
        sql语句查询:
            select Book.title,Publish.name from Book inner join Publish on
             Book.publish_id = Publish.nid
    
        # 查询每个出版社的名字及其出版书籍的个数
        sql语句查询:
            先join两张表:
            select * from app01_book inner join app01_publish on app01_book.publish_id = app01_publish.nid
            
           nid  title   pub_date    publish_id     price   nid     name    city   tel      email      
            1    python    2018-05-06    1               100      1    人民出版社    北京    1234456    12156@qq.com
            2    java    2018-05-06    14               480        14    海南出版社    海南    1232316    2421356@qq.com
            3    go        2018-08-26    1               450        1    人民出版社    北京    1234456    12156@qq.com
            4    lua        2011-02-16    1              12312        1    人民出版社    北京    1234456    12156@qq.com
            分组查询sql语句:
                select app01_publish.name,Count("title") from app01_book inner join app01_publish on 
                    app01_book.publish_id = app01_publish.nid group by app01_publish.nid
                 结果:   
                 id     name     Count("title") 
                  1  人民出版社        3
                  2  海南出版社        1              
        
        '''

    现在使用ORM语句进行查询:

        # 方式一:通过主键进行分组 然后再获取想要的字段
        # ret = Publish.objects.values("nid").annotate(c=Count("book__title"))
        # print(ret)  # <QuerySet [{'nid': 1, 'c': 3}, {'nid': 14, 'c': 1}, {'nid': 15, 'c': 0}]>
    
        ret = Publish.objects.values("nid").annotate(c=Count("book__title")).values("name","c")
        print(ret)  # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '海南出版社', 'c': 1}, {'name': '天津出版社', 'c': 0}]>
    
        # 方式二:直接根据需分组的字段进行分组
        ret = Publish.objects.values("name").annotate(c=Count("book__title"))
        print(ret)  # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '天津出版社', 'c': 0}, {'name': '海南出版社', 'c': 1}]>

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

        '''
        sql语句查询:
            select name,Max("app01_book".price) from app01_author inner join app01_authordetail on  
            app01_author.authordetail_id = app01_authordetail.nid inner join app01_book on 
            app01_author.nid = app01_book.nid group by app01_author.name
        '''
        ret = Author.objects.values("pk").annotate(max_price=Max("book__price")).values("name","max_price")
        print(ret) # <QuerySet [{'name': 'Tom', 'max_price': Decimal('480')}, {'name': 'Jane', 'max_price': Decimal('480')}, {'name': 'Tone', 'max_price': Decimal('480')}, {'name': 'Jin', 'max_price': Decimal('480')}]>
    
        # 等同于下面语句  
        ret = Author.objects.all().annotate(max_price=Max("book__price")).values("name","max_price")
        print(ret) # <QuerySet [{'name': 'Tom', 'max_price': Decimal('480')}, {'name': 'Jane', 'max_price': Decimal('480')}, {'name': 'Tone', 'max_price': Decimal('480')}, {'name': 'Jin', 'max_price': Decimal('480')}]>
    
        ret = Author.objects.annotate(max_price=Max("book__price")).values("name","max_price")
        print(ret) # <QuerySet [{'name': 'Tom', 'max_price': Decimal('480')}, {'name': 'Jane', 'max_price': Decimal('480')}, {'name': 'Tone', 'max_price': Decimal('480')}, {'name': 'Jin', 'max_price': Decimal('480')}]>

    总结:

    多表分组模型:

    模型一:  
    Author.objects.values("pk"). annotate(max_price=Max("book__price")). values("name","max_price")   关键字“每一个”后的表.objects.values("分组字段").annotate.(聚合函数("关联表__统计字段")).values("需要展示的字段")

    模型二:
      Author.objects.all().      annotate(max_price=Max("book__price")).values("name","max_price")
      关键字“每一个”后的表.objects.all().annotate.(聚合函数("关联表__统计字段")).values("需要展示的字段")
      注意:all()可加可不加,结果都是一样的 不同之处在于下面的写法 values(“”)中的字段可以取根表的所有字段以及统计的字段
    解析:以 关键字“每一个”后的表 为根,通过values()进行分组;
    然后通过分组管理器(annotate)配合聚合函数获取“关联表的统计字段”的数据
    最后使用values("字段")获取需要的字段数据

    extra方法:

    在Django中,有些时间查询语句是ORM无法完成转换的,就像获取在datatime中的年月日,直接从数据库是无法查询的,我们可以个extra方法

    格式: extra(select = {"自定义字段":“date_format(‘时间字段’,'%%Y-%%m-%%d')”}): 

    extra是将Queryset对象增加 一个自定义的字段,返回的结果还是Queryset对象。

    date_list  = Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y/%%m/%%d')"}).values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date","c")
    print(date_list)
    #结果
    <QuerySet [('2020/03/23', 1)]>

     TruncMonth方法

    除了extra方法之外,Django还给我们封装了一个”TruncMonth “方法

      from django.db.models.functions import TruncMonth 

    在上图中, TruncMont把“timestamp”进行截取,只截取到月份,然后赋值给month,原理和extra一样,也是增加了一个键值对,返回的也是Queryset对象

        ret = models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate(
            c=Count("nid")).values_list("month", "c")
        print("ret----->",ret)
        # 结果
        <QuerySet [(datetime.datetime(2020, 3, 1, 0, 0), 1)]>

    ===================== F与Q查询 ==================

    F查询:

        # 查询评论数大于阅读数的书籍
    
        ret = Book.objects.all().filter(comment_num__gt=F("read_num"))
        print(ret)  # <QuerySet [<Book: python>, <Book: go>]>
    
        # 将所有书籍的价格增加20
        ret = Book.objects.update(price=F("price")+20)

    Q查询:

    Q有三种关联方式:且、或、非

    且:和符号  “ & 匹配使用,用户连接多个参数

    或:和符号 ”|“ 匹配使用,用于选择多个条件中的一个

    非:和符号”~“ 匹配使用,用户否定某条件,后面必须跟 ”|“符号

    示例:

        from django.db.models import Q
    
        # 查询书名为python 且 价格为120的书籍  python    120
    
      #方式一:正常写法
     
        ret = Book.objects.filter(title="python",price=220).values("title","price")
        print(ret)  # <QuerySet [{'title': 'python', 'price': Decimal('220.00')}]>

      # 方式二:使用 Q ret = Book.objects.filter(Q(title="python") & Q(price=220)).values("title","price") print(ret) # <QuerySet [{'title': 'python', 'price': Decimal('220.00')}]> # 查询书名为python 或者 价格为120的书籍 ret = Book.objects.filter(Q(title="python") | Q(price=120)).values("title","price") print(ret) # <QuerySet [{'title': 'python', 'price': Decimal('220.00')}]> # 查询书名非python 或者 价格为120的书籍 ret = Book.objects.filter(~Q(title="python") | Q(price=120)).values("title","price") print(ret) # <QuerySet [{'title': 'java', 'price': Decimal('600.00')}, {'title': 'go', 'price': Decimal('220.00')}, # {'title': 'lua', 'price': Decimal('12432.00')}]>


  • 相关阅读:
    PAT 天梯赛 L1-002 【递归】
    HDU_2717_Catch That Cow
    Stock Exchange (最大上升子子串)
    Lorenzo Von Matterhorn(map的用法)
    Ignatius and the Princess IV (简单DP,排序)
    投掷硬币(概率dp)
    Find The Multiple (DFS递归)
    24 Game
    棋盘问题
    linux上的文件服务
  • 原文地址:https://www.cnblogs.com/fanhua-wushagn/p/12493775.html
Copyright © 2011-2022 走看看