微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

python day55

今日内容

如何写一个测试脚本?

创建一个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=‘‘,create_time=2019-5-1) book_obj.save() # 2.验证时间格式字段即可以传字符串也可以传时间对象
import datetime ctime = datetime.datetime.Now() book = models.Book.objects.create(name=‘‘,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() 因为一个作者对应着多个图书

连续跨表查询

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

总结:

基于双下划线的查询

一对一用连表查询

  • 一对一双下划线查询
    • 正向:按字段,跨表可以在filter,也可以在values中
    • 反向:按表名小写,也可以在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查询

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

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关系

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐