• 写测试脚本/单表操作(双下滑线查询)/多表操作/ORM跨表查询(基于双下划线的查询,F查询,Q查询)******


    如何写一个测试脚本?

    创建一个test.py文件

    from django.test import TestCase
    ​
    # Create your tests here.
    import os
    ​
    ​
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings文件路径")
        import django
        django.setup()
        """在下面就可以写针对某一个py文件的测试代码"""
        from app01 import models

    搞定了!!!

    模型层

    13个方法

    all()
    filter()
    get()
    reverse()
    order_by()
    exclude()
    values()
    values_list()
    count()
    distinct()
    exists()
    first()
    last()

    演示表

    from django.db import models
    ​
    # Create your models here.
    class Book(models.Model):
        title = models.CharField(max_length=255)
        price = models.DecimalField(max_digits=8,decimal_places=2)
        publish_date = models.DateField(auto_now_add=True)
    ​
        # 库存数
        kucun = models.IntegerField(null=True)
        # 卖出数
        maichu = models.IntegerField(null=True)
    ​
        publish = models.ForeignKey(to='Publish')  # 默认是跟publish的主键字段做的一对多外键关联
        authors = models.ManyToManyField(to='Author')
        # 虚拟字段      1.自动创建第三张表    2.帮助orm跨表查询
    def __str__(self):
            return self.title
    ​
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        addr = models.CharField(max_length=32)
        # email = models.EmailField()  # 就是varchar(254)
    def __str__(self):
            return self.name
    ​
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDetail')
    ​
        def __str__(self):
            return self.name
    class AuthorDetail(models.Model):
        phone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
        """
        models.py中的模型类__str__方法 必须返回一个字符串形式数据!!!
        
        """
        def __str__(self):
            return self.addr

    单表操作

    新增数据

    # 第一种:有返回值,并且就是当前被创建的数据对象
    modles.Book.objects.create(name='',price='',publish='',author='',create_time='2019-5-1')
    # 第二种:先实例化产生对象,然后调用save方法保存
    book_obj = models.Book(name='',price='',publish='',author='',create_time='2019-5-1')
    book_obj.save()
    # 2.验证时间格式字段即可以传字符串也可以传时间对象
    import datetime
    ctime = datetime.datetime.now()
    book = models.Book.objects.create(name='',price='',author='',create_time=ctime)

    删除数据

    # 1.删除书名为xxx的这本书  queryset方法
    res = models.Book.objects.filter(name='').delete()
    # 2.删除书名为xxx的这本书  queryset方法
    res = models.Book.objects.filter(name='').first()
    res.delete()

    修改数据

    # 1.queryset修改
    models.Book.objects.filter(name='').update(price='')
    # 2.对象修改
    book = models.Book.objects.filter(name='').first()
    book.price = 66.66
    book.save()  # 对象只有保存方法 这样也能实现修改需求

    查询数据

    <1> all():                  查询所有结果
    <2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
    <3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误
    <4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
    <5> order_by(*field):       对查询结果排序('-id')/('price')
    <6> reverse():              对查询结果反向排序   >>>前面要先有排序才能反向
    <7> count():                返回数据库中匹配查询(QuerySet)的对象数量
    <8> first():                返回第一条记录
    <9> last():                返回最后一条记录
    <10> exists():              如果QuerySet包含数据,就返回True,否则返回False
    <11> values(*field):        返回一个ValueQuerySet(一个特殊的QuerySet),运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
    <12> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    <13> distinct():            从返回结果中剔除重复纪录
    # 必须完全一样才可以去重(意味着带了id就没有意义了)
    # res = models.Book.objects.all().values('name').distinct()  先查一个重复的值再去重

    双下滑线查询

    查看orm内部sql语句的方法有哪些?

    • 1.如果是queryset对象,那么可以点query直接查看该queryset的内部sql语句
    • 2.在django项目的配置文件中,配置一下参数即可实现所有的orm在查询的时候自动打印对应的sql语句
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }

    查询价格大于200的书籍

    res = models.Book.objects.filter(price__gt=200)

    查询价格小于200的书籍

    res = models.Book.objects.filter(price__lt=200)

    查询价格大于等于200.22的书籍

    res = models.Book.objects.filter(price__gte=200.22)

    查询价格小于等于200.22的书籍

    res = models.Book.objects.filter(price__lte=200.22)

    查询价格要么是200,要么是300,要么是666.66

    res = models.Book.objects.filter(price__in=[200,300,666.66])

    查询价格在200到800之间的

    res = models.Book.objects.filter(price__range=(200,800))  # 两边都包含

    查询书籍名字中包含p的

    res = models.Book.objects.filter(title__contains='p')  # 仅仅只能拿小写p
    res = models.Book.objects.filter(title__icontains='p')  # 忽略大小写

    查询书籍是以三开头的,或者以P结尾的

    res = models.Book.objects.filter(title__startswith='')
    res1 = models.Book.objects.filter(title__endswith='p')

    查询出版日期是2017的年

    res = models.Book.objects.filter(create_time__year='2017')

    多表操作

    图书管理系统表创建

    • 一对多:ForeignKey

    • 一对一:OnoToOneField,可以用ForeignKey代替ForeignKey(unique=True)

      • 上面两个关键字所创建出来的字段会自动加上_id后缀

    • 多对多:ManyToManyFiled

      • 该字段并不会真正的在表中展示出来 它仅仅是一个虚拟字段

        • 1.告诉orm自动创建第三种表

        • 2.帮助orm跨表查询

    1.一对多的书籍记录增删改查

    # 针对外键关联的字段 两种添加方式
    # 第一种通过publish_id
    # 第二种通过publish传出版社对象
    # 删除书籍直接查询删除即可,删除出版社会级联删除
    # 编辑数据也是两种对应的方式(对象点的方式(这里能点publish和publish_id)最后点save(),queryset方式update())

    2.多对多的书籍与作者的增删改查

    """前提:先获取书籍对象,再通过书籍对象点authors来进行书籍作者的增删改查"""
    # 1.给书籍新增作者add
      # 1.add可以传作者id,也可以直接传作者对象,并且支持传多个位置参数(不要混着用)
      
    # 2.给书籍删除作者remove
        # 1.remove同样可以传id,对象,并且支持传多个位置参数(不要混着用)
    # 3.直接清空书籍对象所有的作者数据clear()不用传任何参数
    # 4.修改书籍对象所关联的作者信息set,注意点set括号内必须传可迭代对象,里面可以传id,对象
        
    """总结:一对多增删改,多对多add,remove,clear,set"""

    ORM跨表查询

    基于对象的跨表查询

    正向查询与反向查询

    • 正向查询按字段,反向查询按表名小写

    正向与方向的概念解释

    # 一对一
    # 正向:author---关联字段在author表里--->authordetail     按字段
    # 反向:authordetail---关联字段在author表里--->author     按表名小写
    ​
    ​
    # 一对多
    # 正向:book---关联字段在book表里--->publish      按字段
    # 反向:publish---关联字段在book表里--->book      按表名小写_set.all() 因为一个出版社对应着多个图书
    # 多对多
    # 正向:book---关联字段在book表里--->author       按字段
    # 反向:author---关联字段在book表里--->book       按表名小写_set.all() 因为一个作者对应着多个图书

    连续跨表查询

    • 查询图书是三国演义的作者的手机号,先查书,再正向查到作者,在正向查手机号

    总结:

    • 基于对象的查询都是子查询,这里可以用django配置文件自动打印sql语句的配置做演示

    基于双下划线的查询

    一对一用连表查询

    • 一对一双下划线查询
      • 正向:按字段,跨表可以在filter,也可以在values中
      • 反向:按表名小写,跨表可以在filter,也可以在values中

    示例:查询jason作者的手机号

    # 正向
    ret=Author.objects.filter(name='jason').values('authordetail__phone')
    ​
    # 反向
    # 以authordetail作为基表 反向查询,按表名小写  跨表的话,用表名小写
    ret=AuthorDetail.objects.filter(author__name='jason').values('phone')

    示例;查询jason这个作者的性别和手机号

    # 正向
    ret=Author.objects.filter(name='jason').values('sex','authordetail__phone')

    示例:查询手机号是130的作者性别

    # 正向
    ret=Author.objects.filter(authordetail__phone='13888888').values('sex')
    ​
    # 反向
    ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex')

    总结:

    • 其实你在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名来查即可

    示例1:查询出版社为北方出版社的所有图书的名字和价格

    res1 = Publish.objects.filter(name='').values('book__name','book__price')
    res2 = Book.objects.filter(publish__name='').values('name','price')

    示例2:查询北方出版社出版的价格大于19的书

    res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price)

    聚合查询

    关键词是aggregate

    # 别忘了导入下面的模块
    from django.db.models import Sum,Max,Min,Avg,Count

    示例:

    models.Book.objects.all().aggregate(Avg("price"))

    如果你想要为聚合值指定一个名称,可以向聚合子句提供它

    models.Book.objects.aggregate(average_price=Avg('price'))

    如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

    models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))

    分组查询

    关键词是annotate

    ORM查询示例:

    from django.db.models import Avg
    models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

    示例1:统计每一本书的作者个数

    book_list = models.Book.objects.all().annotate(author_num=Count("author"))
    for obj in book_list:
        print(obj.author_num)

    示例2:统计出每个出版社买的最便宜的书的价格

    publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
    for obj in publisher_list:
        print(obj.min_price)

    示例3:统计不止一个作者的图书

    models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)

    示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序

    models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")

    示例5:查询各个作者出的书的总价格

    models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")

    总结:

    • value里面的参数对应的是sql语句中的select要查找显示的字段,
    • filter里面的参数相当于where或者having里面的筛选条件
    • annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值
    • 只要是queryset对象,就可以无限制的调用queryset对象的方法!!!最最常用的就是对一个已经filter过滤完的数据 再进行更细化的筛选

    F查询

    • F查询的本质就是从数据库中获取某个字段的值
    • 之前查询等号后面的条件都是我们认为输入的 ,现在变成了需要从数据库中获取数据放在等号后面

    示例:查询库存数大于卖出数的书籍

    from django.db.models import F
    res = models.Book.objects.filter(kucun__gt=F('maichu'))

    示例:将书籍库存数全部增加1000

    models.Book.objects.update(kucun=F('kucun')+1000)

    示例:把所有书名后面加上'新款'

    from django.db.models.functions import Concat
    from django.db.models import Value
    ​
    ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
    ​
    # 不能这么写,数据会变成0
    models.Book.objects.update(title = F('title')+'新款')

    Q查询

    示例:查询书籍名称是三国演义或者价格是444.44

    from django.db.models import Q
    ​
    # filter只支持and关系,这种情况下下面代码的返回结果只会是空[]
    res = models.Book.objects.filter(title='三国演义',price=444.44)
    ​
    # 如果用逗号 那么还是and关系,返回值依然为空[]
    res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444))
    ​
    # 用"|"就变为"或"关系了,返回结果正常
    res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444))
    ​
    # 在Q前面加"~"就是not的意思
    res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))

    Q查询的高级用法

    q = Q()
    q.connector = 'or'  # 修改查询条件的关系,默认是and
    q.children.append(('title__contains','三国演义'))  # 往列表中添加筛选条件
    q.children.append(('price__gt',444))  # 往列表中添加筛选条件
    res = models.Book.objects.filter(q)  # filter支持你直接传q对象,但是默认还是and关系
  • 相关阅读:
    列表和元组
    UVM宏
    UVM中重要函数
    组合模式(composite)
    装饰器模式(Decorator)
    适配器模式(Adapter)
    桥接模式
    原型模式(prototype)
    单例模式(singleton)
    UML类图
  • 原文地址:https://www.cnblogs.com/zhukaijian/p/11552494.html
Copyright © 2020-2023  润新知