zoukankan      html  css  js  c++  java
  • ORM操作

    单表使用ORM对数据库的增删改查

    ORM与数据库的对应

    类     ==>  表

    对象    ==>  记录

    属性  ==>  字段

    from django.db import models
    
    
    class Publisher(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32, unique=True)
    
    
    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32, unique=True)
        publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
        # publisher为外键,ORM自动将publisher后面加上_id作为字段传给数据库,可以使用book_obj.publisher_id找到书籍对象对应的出版社的id,这是直接操作数据库的
        # publisher作为ORM中BOOK类的属性,可以通过book_obj.publisher找到书籍对象对应的出版社对象,这仍然是通过ORM操作数据库
        def __repr__(self):
            return "<Book object: {} >".format(self.title)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32, unique=True)
        books = models.ManyToManyField('Book')
    
        def __repr__(self):
            return "<Author object: {} >".format(self.name)
    
        __str__ = __repr__
        
    增:
        普通表:            models.Publisher.objects.create(name='xxx')    
        
        带外键的表:        models.Book.objects.create(name='xxx',publisher=publisher_obj)
                        models.Book.objects.create(name='xxx',publisher_id=publisher_obj.id)
        
        带多对多的表:    author_obj = models.Author.objects.create(name='xxxxx')
                        author_obj.books.set([1,3,4])
        
    删除:
        对象列表.delete()
        对象.delete()
        
    修改:
        普通表:            pub_obj.name='xxxxx'
                        pub_obj.save()
    
        带外键的表:        book_obj.title = 'xxxxx'
                        book_obj.publisher = publisher_obj 或
                        book_obj.publisher_id = publisher_obj.id  或 book_obj.publisher_id = 'id的数值'(推荐这种写法,直接操作数据库)
                        book_obj.save()
        
        带多对多的表    author_obj.name = 'xxx'
                        author_obj.save()    
                        author_obj.books.set([1,3,4])
                        
    查:
        普通字段:        pub_obj.id
        
        外键字段:        book_obj.publisher       —— 》 关联的出版社对象
                        book_obj.publisher_id    —— 》 关联的出版社对象的id
                        
        多对多字段:        author_ob.books             —— 》 管理对象 
                        author_ob.books.all()     —— 》 作者关联的所有书籍对象列表  
                

    常用字段 

    AutoField

    自增的整形字段,必填参数primary_key=True,则成为数据库的主键。无该字段时,django自动创建。

    一个model不能有两个AutoField字段。

    IntegerField

    一个整数类型。数值的范围是 -2147483648 ~ 2147483647。

    CharField

    字符类型,必须提供max_length参数。max_length表示字符的长度。

    DateField

    日期类型,日期格式为YYYY-MM-DD,相当于Python中的datetime.date的实例。

    参数:

    • auto_now:每次修改时修改为当前日期时间。
    • auto_now_add:新创建对象时自动添加当前日期时间。

    auto_now和auto_now_add和default参数是互斥的,不能同时设置。

    DatetimeField

    复制代码
        AutoField(Field)
            - int自增列,必须填入参数 primary_key=True
    
        BigAutoField(AutoField)
            - bigint自增列,必须填入参数 primary_key=True
    
            注:当model中如果没有自增列,则自动会创建一个列名为id的列
            from django.db import models
    
            class UserInfo(models.Model):
                # 自动创建一个列名为id的且为自增的整数列
                username = models.CharField(max_length=32)
    
            class Group(models.Model):
                # 自定义自增列
                nid = models.AutoField(primary_key=True)
                name = models.CharField(max_length=32)
    
        SmallIntegerField(IntegerField):
            - 小整数 -32768 ~ 32767
    
        PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
            - 正小整数 0 ~ 32767
    
        IntegerField(Field)
            - 整数列(有符号的) -2147483648 ~ 2147483647
    
        PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
            - 正整数 0 ~ 2147483647
    
        BigIntegerField(IntegerField):
            - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
    
        BooleanField(Field)
            - 布尔值类型
    
        NullBooleanField(Field):
            - 可以为空的布尔值
    
        CharField(Field)
            - 字符类型
            - 必须提供max_length参数, max_length表示字符长度
    
        TextField(Field)
            - 文本类型
    
        EmailField(CharField):
            - 字符串类型,Django Admin以及ModelForm中提供验证机制
    
        IPAddressField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
    
        GenericIPAddressField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
            - 参数:
                protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
                unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
    
        URLField(CharField)
            - 字符串类型,Django Admin以及ModelForm中提供验证 URL
    
        SlugField(CharField)
            - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
    
        CommaSeparatedIntegerField(CharField)
            - 字符串类型,格式必须为逗号分割的数字
    
        UUIDField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
    
        FilePathField(Field)
            - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
            - 参数:
                    path,                      文件夹路径
                    match=None,                正则匹配
                    recursive=False,           递归下面的文件夹
                    allow_files=True,          允许文件
                    allow_folders=False,       允许文件夹
    
        FileField(Field)
            - 字符串,路径保存在数据库,文件上传到指定目录
            - 参数:
                upload_to = ""      上传文件的保存路径
                storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
    
        ImageField(FileField)
            - 字符串,路径保存在数据库,文件上传到指定目录
            - 参数:
                upload_to = ""      上传文件的保存路径
                storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
                width_field=None,   上传图片的高度保存的数据库字段名(字符串)
                height_field=None   上传图片的宽度保存的数据库字段名(字符串)
    
        DateTimeField(DateField)
            - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
    
        DateField(DateTimeCheckMixin, Field)
            - 日期格式      YYYY-MM-DD
    
        TimeField(DateTimeCheckMixin, Field)
            - 时间格式      HH:MM[:ss[.uuuuuu]]
    
        DurationField(Field)
            - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    
        FloatField(Field)
            - 浮点型
    
        DecimalField(Field)
            - 10进制小数
            - 参数:
                max_digits,小数总长度
                decimal_places,小数位长度
    
        BinaryField(Field)
            - 二进制类型
    详细字段类型
    #自定义一个char类型字段:
    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
    #使用自定义char类型字段:
    class Class(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=25)
        # 使用自定义的char类型的字段
        cname = MyCharField(max_length=25)
        null                数据库中字段是否可以为空
        db_column           数据库中字段的列名
        default             数据库中字段的默认值
        primary_key         数据库中字段是否为主键
        db_index            数据库中字段是否可以建立索引
        unique              数据库中字段是否可以建立唯一索引
        unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
        unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
        unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
     
        verbose_name        Admin中显示的字段名称
        blank               Admin中是否允许用户输入为空
        editable            Admin中是否可以编辑
        help_text           Admin中该字段的提示信息
        choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                            如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
     
        error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                            字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                            如:{'null': "不能为空.", 'invalid': '格式错误'}
     
        validators          自定义错误验证(列表类型),从而定制想要的验证规则
                            from django.core.validators import RegexValidator
                            from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
                            MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                            如:
                                test = models.CharField(
                                    max_length=32,
                                    error_messages={
                                        'c1': '优先错信息1',
                                        'c2': '优先错信息2',
                                        'c3': '优先错信息3',
                                    },
                                    validators=[
                                        RegexValidator(regex='root_d+', message='错误了', code='c1'),
                                        RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
                                        EmailValidator(message='又错误了', code='c3'), ]
                                )
     
    字段参数
    字段参数

    Model Meta参数

    app01 下的models.py
    class
    UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # admin中显示的表名称 verbose_name = '个人信息' # verbose_name加s verbose_name_plural = '所有用户信息' # 联合索引 index_together = [ ("pub_date", "deadline"), # 应为两个存在的字段 ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # 应为两个存在的字段

    普通索引:仅加速查询

    唯一索引:加速查询 + 列值唯一(可以有null)

    主键索引:加速查询 + 列值唯一 + 表中只有一个(不可以有null)

    组合索引:多列值组成一个索引,
                  专门用于组合搜索,其效率大于索引合并

    全文索引:对文本的内容进行分词,进行搜索 


    查询的13条命令 

    不必非在app下的models进行ORM操作,可以在项目目录下新建文件夹,新建py文件进行ORM操作

    我们在django中运行项目都是通过manage.py来完成的,下面的代码设置的一些环境在manage.py中也有,可以直接粘过来

    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings") # orm_practice是当前的项目名
        import django
        django.setup()
    
        from app01 import models
    
    
        # all  获取所有对象   ——》 QuerySet
        ret = models.Person.objects.all()
    
        # get  获取单独的对象  ——》 对象
        # 找不到或者找到多个就报错
        ret= models.Person.objects.get(id=1,name='阿旭')
    
        # filter 过滤 获取所有满足条件的对象   ——》QuerySet
        ret = models.Person.objects.filter(id=1)
    
        # exclude  获取不满足条件的所有对象
        ret = models.Person.objects.exclude(id=1)
    
        # values   ——》QuerySet  元素是字典
        # 不写参数   默认所有字段的名字和值
        # 写参数     拿到指定字段的名字和值
        ret = models.Person.objects.all().values('id','name')
        ret = models.Person.objects.values('id','name')
        # values_list   ——》QuerySet  元素是元组  只有值没有字段名
        # 不写参数   默认所有字段值
        # 写参数     拿到指定字段值
        ret = models.Person.objects.values_list('name','id')
        # print(ret)
    
        # for i in ret :
        #     print(i,type(i))
        #  reverse 对已经排序的QuerySet进行反转
        ret = models.Person.objects.all().reverse()
    
    
        # distinct 去重  ——》QuerySet
    
    
        # count 对QuerySet中的元素进行计数
        ret = models.Person.objects.filter(id=100).count()
    
    
        # first  取QuerySet中的第一个元素
        ret = models.Person.objects.all().first()
    
        # last  取QuerySet中的最后一个元素
        ret = models.Person.objects.all().last()
        ret = models.Person.objects.values_list().last()
    
        ret = models.Person.objects.filter(id=100).first()
    
        # exists 判断查询结果是否有值
        ret = models.Person.objects.filter(id=100).exists()
        # print(ret)
    
        # order_by 按字段进行排序 ——》QuerySet
        ret =models.Person.objects.order_by('age')
        print(ret)
    """
    返回是QuerySet的方法
    1. all()
    2. filter()
    3. values()
    4. values_list()
    5. order_by()
    6. distinct()
    7. reverse()
    8. exclude()
    
    返回是对象
    1. get()
    2. first()
    3. last()
    
    返回是布尔值
    1. exists()
    
    返回是数字
    1. count()
    
    """

     单表的双下划线

    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
        import django
    
        django.setup()
    
        from app01 import models
    
        ret = models.Person.objects.filter(id__lt=3)  # less than
        ret = models.Person.objects.filter(id__gt=3)  # great than
    
        ret = models.Person.objects.filter(id__gte=3)  # great than equel
        ret = models.Person.objects.filter(id__lte=3)  # great than equel
        ret = models.Person.objects.filter(id__gte=3, id__lte=5)
    
        ret = models.Person.objects.exclude(id__gt=5)
    
        ret = models.Person.objects.filter(id__in=[1, 3, 5])
        ret = models.Person.objects.exclude(id__in=[1, 3, 5])
    
        ret = models.Person.objects.filter(id__gte=1, id__lte=100) #并且的关系
        ret = models.Person.objects.filter(id__range=[1, 5])    # id范围在1-5包括1和5
        ret = models.Person.objects.filter(name__contains='A')    # name包含'A'类似于sql语句中的like
        ret = models.Person.objects.filter(name__icontains='a')    # name中包含'A'或'a',不区分大小写
    
        ret = models.Person.objects.filter(name__istartswith='a')    # 以'a'开头
        ret = models.Person.objects.filter(name__endswith='x')        # 以'x'结尾
    
        ret = models.Person.objects.filter(birth__year='2018')        # 筛选年份为'2018'日期的对象
        ret = models.Person.objects.filter(birth__month='09')        # 筛选月份为'09'日期的对象
        ret = models.Person.objects.filter(name__isnull=True)        # 筛选名字不为空的对象
        print(ret)

    跨表查询(连表查询)中的双下划线表示另一个关联表(外键关联或多对多关联)中的字段.

    如ret= models.Book.objects.filter(publisher__name='沙河出版社')    publisher__name表示publisher表中的name字段   这个语句的意思是筛选出所有 出版社为沙河出版社出版的书籍

    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
        import django
    
        django.setup()
    
        from app01 import models
        # 正向查询   book ——》 publisher
        # 基于对象查询
        book_obj = models.Book.objects.get(id=1)
        print(book_obj.id)
        print(book_obj.title)
        print(book_obj.publisher_id)
        print(book_obj.publisher_id)  # 关联的出版社对象
        print(book_obj.publisher.id)  # 关联的出版社对象
        print(book_obj.publisher.name)
    
        # 基于字段查询
        ret= models.Book.objects.filter(publisher__name='沙河出版社')
        ret= models.Book.objects.filter(publisher_id=1)
        print(ret)
    
    
        
        
        
        
        # 反向查询   publisher ——》 book
        # 基于对象的查询
        # 1 —— 》 多    表名小写_set ——》 管理对象   .all()  出版社关联的所有书籍对象
        pub_obj = models.Publisher.objects.first()
    
        # 表名小写_set ,注意是表名小写_set  而不是子表(多对一中的多)的外键名_set   
        ret = pub_obj.book_set.all()        
        print(pub_obj.book_set,type(pub_obj.book_set))   book_set是外键反向查询的管理对象
        print(ret)
    
        class Book(models.Model):
        title = models.CharField(max_length=32)
        publisher = models.ForeignKey('Publisher',
                                      related_name='books',      # 关联名字
                                      # related_query_name='xx',    #关联查询名字
                                      on_delete=models.CASCADE, null=True)
        
        # Class Book中指定了related_name  books
        # print(pub_obj.books.all())
        
        
    
        # 基于字段的查询
        #1,不指定related_name和related_query_name
        ret = models.Publisher.objects.filter(book__title='跟太亮学开车')   表名
        #2,指定related_name  不指定related_query_name
        ret = models.Publisher.objects.filter(books__title='跟太亮学开车')  使用related_name 指定的名字 'books'
        #3,指定related_name和related_query_name
        ret = models.Publisher.objects.filter(xx__title='跟太亮学开车')        使用related_query_name 指定的名字 'xx'
        print(ret)
    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
        import django
    
        django.setup()
    
        from app01 import models
        author_obj = models.Author.objects.get(id=1)
        # print(author_obj.books.all())   books是多对多管理对象
    # 多对多中的 creat() add() remove() clear()
        # create()
        # author_obj.books.create(title='戴绿与嫂子的故事',publisher_id=1)
        # 1. 创建书籍对象(与出版社进行关联)
        # 2. 该对象和作者进行关联
    
        
        # add()
        book_list = models.Book.objects.filter(id__in=[1,6,8,9])
        author_obj.books.add(*books_list)  # 增加作者对应的书籍  可以写id 可以写对象,book_list是对象列表,需要用*打散
    
        # set()
        author_obj.books.set([1,6,8,9])     # 用书籍id设置作者对应的书籍
        author_obj.books.set(books)
        author_obj.books.remove(*books)
        author_obj.books.clear()
        
    # 一对多中的 creat() remove() clear()
        pub_obj= models.Publisher.objects.first()
        pub_obj.book_set        book_set是反向查询的管理对象
        pub_obj.books.create(title='跟老男孩学思想')
        
        pub_obj = models.Publisher.objects.get(id=1)
    
        # 一对多的管理对象remove不能使用id  使用对象
        pub_obj.books.remove(models.Book.objects.get(id=5))
    
        pub_obj.books.clear()    # 清空关联的书籍
        

    聚合和分组

    聚合:aggregate(*args,**kwargs)
      通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
      聚合的结果不包含原来表中的字段,aggregate()是QuerySet 的一个终止子句,只能在最后写他
    分组:annotate(*args,**kwargs):
      可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
      对分组后的每一组进行查询计算,然后将结果作为注释添加到表每行的数据中

    简单看下用法,详细用法见下面的练习代码

    #查询alex出的书的总价格
    Book.object.filter(authors__name='alex').aggregate(Sum('price'))
    #查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是anthors__name
    Book.object.values('authors__name').annotate(Sum('price'))
    #查询各个出版社最便宜的书价是多少
    Book.object.values('publisher__name').annotate(Min('price'))
    

    F查询和Q查询

      

    #仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F查询和Q查询
    # F 使用查询条件的值,专门取对象中某列值的操作
    models.Tb1.objects.update(num=F('num')+1)  # 将num加1后重新赋值给num
    # Q 构建搜索条件
    models.Book.objects.filter(Q(id__lt=3)|Q(id__gt=5)).values()	# filter中两个条件以逗号分隔是and的关系,使用Q查询可以有或的关系
    
    import os
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
        import django
    
        django.setup()
    
        from app01 import models
        from django.db.models import F,Q
        ret = models.Book.objects.filter(sale__gt=50).values()   # 一个字段的比较不用使用F查询
        ret = models.Book.objects.filter(sale__gte=F('kucun')+30).values()   # 两个字段的值进行比较需要使用F查询	
    	
    
        ret = models.Book.objects.filter(~Q(id__lt=3)|Q(id__gt=5)).values()   # ~是取反   和!意义一样
        for i in ret:
            print(i)
    	
    	
    	# updata()和save()的区别,updata只修改条件内的表的字段,save是把所有的字段都再保存一遍
        # models.Book.objects.all().update(sale=100)
        # book_obj = models.Book.objects.get(id=1)
        # book_obj.sale=0
        # book_obj.save()
        # models.Book.objects.all().update(sale=(F('sale')+10)*2)
    
       
    

      详细说明

    # F 使用查询条件的值,专门取对象中某列值的操作
    
        from django.db.models import F
        models.Tb1.objects.update(num=F('num')+1)
    
    # Q 构建搜索条件
        from django.db.models import Q
        
        # 1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
        q1 = models.Book.objects.filter(Q(title__startswith='P')).all()
        print(q1)  # [<Book: Python>, <Book: Perl>]
        
        # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
        Q(title__startswith='P') | Q(title__startswith='J')
        
        # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
        Q(title__startswith='P') | ~Q(pub_date__year=2005)
    
        # 4、应用范围:
        
        # Each lookup function that takes keyword-arguments (e.g. filter(),
        #  exclude(), get()) can also be passed one or more Q objects as
        # positional (not-named) arguments. If you provide multiple Q object
        # arguments to a lookup function, the arguments will be “AND”ed
        # together. For example:
    
        Book.objects.get(
            Q(title__startswith='P'),
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
        )
    
        # sql:
        # SELECT * from polls WHERE title LIKE 'P%'
        #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
        
        # import datetime
        # e=datetime.date(2005,5,6)  #2005-05-06
        
        # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
        # 正确:
        Book.objects.get(
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
            title__startswith='P')
        # 错误:
        Book.objects.get(
            question__startswith='P',
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
    

    事务

     通过事务我们可以把两件或者两件以上的ORM操作组成一个原子,这几件事要么都成功,一旦有一个失败了,那么全部不执行,即使执行过了也要回滚回去

    比如,我们操作数据库进行转账操作,A向B转账分为两步,A的账户扣钱,B的账户加钱,这两件事必须都成功,或者都失败

    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
        import django
    
        django.setup()
    
        from app01 import models
    
        try:
            from django.db import transaction		# 导入从django事务模块
            import datetime
    
            with transaction.atomic():
                new_publisher = models.Publisher.objects.create(name="火星出版社") # 这条语句单独是可以成功的
                models.Book.objects.create(title="橘子物语",
                                           publisher_id=100)  # 指定一个不存在的出版社id,这条语句会报错,所以作为整体,事务内所有语句都不会执行
        except Exception as e:
            print(str(e))
    

      


    ORM查询练习

    简单说明:    publisher     字段   id    name   city

          book            字段   id    title    publish_date     price     memo      publisher(外键关联了publisher)    author(多对多管理对象,关联了作者)

          author          字段    id   name    age      phone

    import os
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_homework.settings")
    import django
    
    django.setup()
    
    from app01 import models
    from django.db.models import Q, Max, Count
    
    
    # 查找所有书名里包含金老板的书
    ret = models.Book.objects.filter(title__contains='金老板')
    
    # 查找出版日期是2018年的书
    ret = models.Book.objects.filter(publish_date__year=2018)
    
    # 查找价格大于10元的书
    ret = models.Book.objects.filter(price__gt=10)
    
    # 查找memo字段是空的书
    # -----字段为空包括空字符串和null  , null和空字符串并不是一回事
    ret = models.Book.objects.filter(Q(memo='') | Q(memo__isnull=True))
    
    # 查找名字以沙河开头的出版社
    # ----distinct去重,有两个名字相同但是id不同的沙河出版社对象,所以这个去重并不能给对象去重,需要先使用values()取出出版社的名字,这样变成字典后再对名字进行去重
    ret = models.Publisher.objects.filter(name__startswith='沙河').values('name').distinct()
    
    # 查找“沙河出版社”出版的所有书籍
    # ----连表查询,使用另一个表的属性时要使用双下划线
    ret = models.Book.objects.filter(publisher__name='沙河出版社')
    
    
    # 查找每个出版社出版价格最高的书籍价格
    # ----annotate分组聚合,分组后就一定要使用聚合函数,annotate在官方文档的意思是注释的意思,给表中每行的数据添加注释
    # ----对annotate前的表进行分组,annotate前有values的话,是以values中的值进行分组,没有values默认以annotate前表的id进行分组
    ret = models.Publisher.objects.annotate(max=Max('book__price')).values('name', 'max', )
    
    ret = models.Book.objects.values('publisher__name').annotate(max=Max('price')).values('publisher_id', 'max', 'title')
    # 查找每个出版社出版价格最高的书籍价格,这是我之前做的方法,也是正确的可以相较而看
        # 单表分组,book表以publisher_id分组,统计每组的最大价格,注意后面的values()中不要包含book表的字段(如果后面的values中包含了book的字段如'title',那么会以 'publisher_id'和'title'一起进行分组,这样就乱了)
        # 这种方法有个问题是不同publisher_id但是同一个出版社名字的不会被分到一组
        ret = models.Book.objects.values('publisher_id').annotate(Max('price')).values('publisher_id','max')
        # 连表分组,book表和publisher表联合,以publisher表的name进行分组,统计每组的最大价格,正确答案,也符合sql语句的查询逻辑
        ret = models.Book.objects.values('publisher__name').annotate(Max('price')).values('publisher_id','max')
        # 单表分组,连表查询 ,以publisher表的id进行分组,查询book的最大价格,同样也是有不同publisher_id但是同一个出版社名字的不会被分到一组的问题
        ret = models.Publisher.objects.annotate(Max('book__price')).values('book__price__max')
        # 单表分组,连表查询 ,以publisher表的name进行分组,查询book的最大价格,不会有上述问题,比较符合人的逻辑
        ret = models.Publisher.objects.values('name').annotate(Max('book__price')).values('book__price__max')
    
    
    
    # 查找每个出版社的名字以及出的书籍数量
    # ----这里的Count计数的是以publisher分组的book对象,
    ret = models.Publisher.objects.annotate(count=Count('book')).values()
    
    
    # 查找书名是“跟金老板学开车”的书的出版社出版的其他书籍的名字和价格
    # ---1,找到出版了“跟金老板学开车”的书的出版社 models.Publisher.objects.get(book__title='跟金老板学开车')
    # ---2,筛选出是上述出版社出版的书,使用publisher出版社对象进行筛选  models.Book.objects.filter(publisher=models.Publisher.objects.get(book__title='跟金老板学开车')
    # ---3.在这些书里排除 '跟金老板学开车'的书  .exclude(title='跟金老板学开车')
    ret = models.Book.objects.filter(publisher=models.Publisher.objects.get(book__title='跟金老板学开车')).exclude(
        title='跟金老板学开车').values('title', 'price')
    
    # 法2
    # ---1,找到出版了“跟金老板学开车”的书的出版社
    # ---2,通过外键book_set 找到该出版社出版的所有书籍,此时的对象列表已经不是出版社,而是书籍
    # ---3,排除 '跟金老板学开车'的书 
    ret = models.Publisher.objects.get(book__title='跟金老板学开车').book_set.exclude(title='跟金老板学开车').values('title', 'price')
    
    
    # 查找书名是“跟金老板学开车”的书的作者们的姓名以及出版的所有书籍名称和价钱
    
    # 这样是有问题的,不能这么写
    ret = models.Author.objects.filter(book__title='跟金老板学开车').values('name', 'book__title', 'book__price').distinct()
    
    # 这样是有问题的,不能这么写,见下面代码
    ret = models.Book.objects.get(title='跟金老板学开车').author.values('name', 'book__title', 'book__price').distinct()
    
    # ---1,找到“跟金老板学开车”的书籍对象
    # ---2,找到写了'跟金老板学开车'书籍的所有的作者对象
    # ---3,在所有书籍中筛选作者在上述作者对象的书籍
    ret = models.Book.objects.filter(
            author__in=models.Author.objects.filter(book=models.Book.objects.filter(title='跟金老板学开车'))).values(
            'author__name', 'title', 'price')        
            
    # 简化
    ret = models.Book.objects.filter(
            author__in=models.Author.objects.filter(book__title='跟金老板学开车')).values(
            'author__name', 'title', 'price')
    # 显示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',
            },
        }
    }
    显示sql语句的命令,在settings中添加下面代码

     补充

    基于双下划线的跨表查询 

    Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

    关键点:正向查询按字段,反向查询按表明。

     

    # 练习1: 查询人民出版社出版过的所有书籍的名字与价格(一对多)

    # 正向查询 按字段:publish

    queryResult=Book.objects
                .filter(publish__name="人民出版社")
                .values_list("title","price")

    # 反向查询 按表名:book

    queryResult=Publish.objects
                  .filter(name="人民出版社")
                  .values_list("book__title","book__price")

    # 练习2: 查询egon出过的所有书籍的名字(多对多)

    # 正向查询 按字段:authors:
    queryResult=Book.objects
                .filter(authors__name="yuan")
                .values_list("title")

    # 反向查询 按表名:book
    queryResult=Author.objects
                  .filter(name="yuan")
                  .values_list("book__title","book__price")


    # 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名


    # 正向查询
    queryResult=Book.objects
                .filter(publish__name="人民出版社")
                .values_list("title","authors__name")
    # 反向查询
    queryResult=Publish.objects
                  .filter(name="人民出版社")
                  .values_list("book__title","book__authors__age","book__authors__name")


    # 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称

    queryResult=Book.objects
                .filter(authors__authorDetail__telephone__regex="151")
                .values_list("title","publish__name")

    注意:

    反向查询时,如果定义了related_name ,则用related_name替换表名,例如: publish = ForeignKey(Blog, related_name='bookList'):

    # 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)

     
        # 反向查询 不再按表名:book,而是related_name:bookList
     
        queryResult=Publish.objects
                  .filter(name="人民出版社")
                  .values_list("bookList__title","bookList__price")
  • 相关阅读:
    EUI组件之DataGroup
    EUI组件之CheckBox
    EUI组件之Button
    EUI组件之BitmapLabel 位图字体
    微信小游戏 egret.getDefinitionByName获取不到
    微信小游戏横屏设置
    本地 win7 与虚拟机Centos7 ping互通和Centos7 上网设置
    Centos7没有ETH0网卡
    Parallels Desktop Centos 设置IP
    2.用Python套用Excel模板,一键完成原亮样式
  • 原文地址:https://www.cnblogs.com/perfey/p/9648474.html
Copyright © 2011-2022 走看看