• 写测试脚本/单表操作(双下滑线查询)/多表操作/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关系
  • 相关阅读:
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 88怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 81.0怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 40怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 24.0怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 21.0怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下驱动器试运行提示过速度保护怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下驱动器如何执行绝对值清零
    倍福TwinCAT(贝福Beckhoff)基础教程 松下绝对值驱动器如何做初始化设置
    倍福TwinCAT(贝福Beckhoff)基础教程 松下官方软件开启报错伺服未就绪怎么办
    JAVA Eclipse 启动 Eclipse 弹出“Failed to load the JNI shared library jvm_dll”怎么办
  • 原文地址:https://www.cnblogs.com/zhukaijian/p/11552494.html
Copyright © 2020-2023  润新知