首页 > 其他分享 >Django7-8

Django7-8

时间:2022-12-19 21:45:48浏览次数:59  
标签:models res price Django7 查询 Ajax print

聚合查询

聚合函数:max、min、sum、avg、count

1.使用聚合函数之前需要导入模块

from django.db.models import Max, Min, Sum, Avg, Count

2.聚合函数的使用

聚合函数通常情况下是配合分组一起使用的

3.关键字aggregate

没有分组之前如果单纯的使用聚合函数 需要关键字aggregate

# 1.查询所有书的平均价格
res = models.Book.objects.aggregate(Avg('price'))
print(res)  # {'price__avg': Decimal('183.117778')}

image

res1 = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
print(res1)

image

分组查询

image
报错原因
image

打开MySQL
输入>>>:show variables like '%mode%';

分组有一个特性 默认只能够直接获取分组的字段 其他字段需要使用方法
我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可

1.分组查询

annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数,所有使用前要从django.db.models引入Avg,Max,Count,Sum(首字母大写))。

2.返回值

分组后,用values取值,则返回值是QuerySet书籍类型里面为一个个字典
分组后,用values_list取值,则返回值是QuerySet数据类型里面为一个个元组

MySQl中的limit相当于ORM中的QuerySet数据类型的切片

3.分组查询关键字

annotate()  里面放聚合函数

1.values 或者 values_list 放在 annotate 前面:values 或者 values_list 是声明以什么字段分组,annotate 执行分组。
2.values 或者 values_list 放在annotate后面: annotate 表示直接以当前表的pk执行分组,values 或者 values_list 表示查询哪些字段, 并且要将 annotate 里的聚合函数起别名,在 values 或者 values_list 里写其别名。
3.filter放在 annotate 前面:表示where条件
4.filter放在annotate后面:表示having

跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询

分组练习题

models后面点什么 就按什么分组 
author_num 是我们自己定义的字段 用来存储统计出来的每本书对应的作者个数

1.统计每一本书的作者个数

res = models.Book.objects.annotate(author_num=Count('author__pk')).values('title', 'author_num')
print(res)
res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
print(res1)
"""
    1.按照整条数据分组
        models.Book.objects.annotate()  按照一条条书籍记录分组
    2.按照表中某个字段分组()
        models.Book.objects.values('title').annotate()  按照annotate之前values括号中指定的字段分组
"""

image

2.统计每个出版社卖的最便宜的书的价格

res1 = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res1)

image

3.统计不止一个作者的图书

'''filter在annotate前面则是where 在annotate后面则是having'''
res = models.Book.objects.annotate(author_num=Count('author__pk')).filter(author_num__gt=1).values('title', 'author_num')
print(res)

image

4.查询各个作者出的书的总价格

res = models.Author.objects.annotate(book_sum_price=Sum('book__price')).values('name', 'book_sum_price')
print(res)

image

F与Q查询

导入模块

from django.db.models  import  F,Q

F查询

能够帮助你直接获取到列表中某个字段对应的数据

注意:
在操作字符串类型的数据的时候  F不能够直接做到字符串的拼接

当表中已经有数据的情况下 添加新的字段需要指定一些参数

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateTimeField(auto_now=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    author = models.ManyToManyField(to='Author')
    '''
    当表中已经有数据的情况下 添加新的字段需要指定一些参数
        1.设置字段值存于为空    null=True
        2.设置字段默认值    default=1000
        3.在终端直接给出默认值
    '''
    storage_num = models.IntegerField(verbose_name='库存数', null=True)
    sale_num = models.IntegerField(verbose_name='卖出数目', default=1000)

    def __str__(self):
        return f'对象:{self.title}'

1.查询卖出书大于库存数的书籍

res = models.Book.objects.filter(storage_num__gt = F('sale_num'))
print(res)

image

将所有书籍的价格上涨1000块

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

image
image

给所有书籍名称后面加上爆款后缀
*针对字符串数据无法直接拼接*
image

models.Book.objects.filter().all().update(title=F('title') + '爆款')  # 针对字符串数据无法直接拼接
    # 导入Concat模块
    from django.db.models.functions import Concat
    # 导入Value模块
    from django.db.models import Value
    models.Book.objects.filter().all().update(title=Concat(F('title'), Value('~爆款')))

image

Q查询

可以改变filter括号内多个条件之间的逻辑运算符,还可以将查询的结果改为字符串形式

filter() 等方法中的关键字参数查询都是一起进行"and",如果你需要执行更复杂的查询(例如ORM语句),你可以使用Q对象。

查询卖出数大于100并且价格小于60的书籍

res = models.Book.objects.filter(Q(sale_num__gt = 100), Q(price__lt = 600))
print(res)

image

查询卖出数大于130或者价格小于30的书籍

res = models.Book.objects.filter(Q(sale_num__gt = 130) | Q(price__lt = 30))
print(res)

image

查询卖出数不是大于80或者价格大于600的书籍

res = models.Book.objects.filter(~Q(sale_num__gt = 80) | Q(price__gt = 600))
print(res)

image
总结

,               and关系
|               or关系
~               not关系

Q 默认是and,可以进行修改
    q = Q()
    q.connector = 'or'

Q查询的进阶用法

可以将查询的结果改为字符串形式

from django.db.models import Q
q_obj = Q()  # 1.产生q的对象
q_obj.connector = 'or'  # 默认多个条件的连接是and可以修改为or
q_obj.children.append(('pk', 1))  # 2.添加查询条件
q_obj.children.append(('price__gt', 2000))  # 支持添加多个
res = models.Book.objects.filter(q_obj)  # 查询支持直接填写q对象
print(res)

image

image

ORM查询优化

django  orm默认都是惰性查询
    当orm的语句在后续的代码中 真正需要使用的时候才会执行
django  orm自带limit分页
    减轻数据库端以及服务端的压力

1.ORM查询优化之only(单表)

res = models.Book.objects.only('title', 'price')
print(res)   # queryset [数据对象、数据对象]
for obj in res:
  print(obj.title)  # 点击括号内填写的字段 不走SQL查询
  print(obj.price)
  print(obj.publish_time)   # 可以点击括号内没有的字段获取数据 但是会走SQL查询
  """
  only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询
    但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询 
    如果看到有人只有only查询的话 尽量不要去点括号内没有的字段 因为它每次都会去查询一次
  """

image

image

2.ORM查询优化之defer(单表)

res = models.Book.objects.defer('title', 'price')
print(res)    # [数据对象, 数据对象]
for obj in res:
  print(obj.title)  # 点击括号内填写的字段 走SQL查询
  print(obj.title)  
  print(obj.price)
  print(obj.publish_time)   # 可以点击括号内没有的字段获取数据 不会走SQL查询
  """
    defer与only刚好相反
        数据对象点击括号内出现的字段 每次都会走数据库查询
        数据对象点击括号内没有的字典 不会走数据库查询
  """

image

3.ORM查询优化之select_related(多表)

res = models.Book.objects.all()
for obj in res:
  print(obj.publish.name)  # 每次查询都走数据库
res = models.Book.objects.select_related('authors')  # 先连表后查询封装
"""
select_related括号内只接收外键字段(一对一  一对多) 它会在内部自动拼表 得出的数据对象在点击表中数据的时候都不会再走数据库查询
"""

image
image

for obj in res:
  print(obj.publish.name)
 """
 prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的
 """
res = models.Book.objects.prefetch_related('publish')  # 子查询
for obj in res:
print(obj.publish.name)

image

ORM事务操作

复习:

1.事务的四大特性

A:   原子性
    每个事务都是不可分割的最小单位(同一个事物内的多个操作要么同时成功要么同时失败)
C:   一致性
    事物必须是使数据库从一个一致性状态编导另一个一致性状态,一致性与原子性使密切相关的
 I:   隔离性
    事物与事物之间彼此不干扰
D:  持久性
    一个事物一旦开启,它对数据库中书籍的改变就应该使永久性的

2.开始事务

开启事务:transaction

回滚:rollback

确认:commit

3.开启事务

django orm提供了至少三种开启事务的方式
	方式1:配置文件数据库相关添加键值对		全局有效
       "ATOMIC_REQUESTS": True每次请求所涉及到的orm操作同属于一个事务
	方式2:装饰器							局部有效
       from django.db import transaction
       @transaction.atomic
       def index():pass	
 	方式3:with上下文管理					局部有效
       from django.db import transaction
    	def reg():
    		with transaction.atomic():
             pass

ORM常用字段类型

1.AutoField(int自增列)
	int自增列,必须填入参数primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。

2.CharField(varchar)
	verbose_name:字段的注释
	max_length:字符长度

3.IntegerField(int)
	一个整数类型, -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)

4.BigIntegerField(bigint)


5.DecimalField(decimal)
	max_digits=8:总共位数
	decimal_places=2:小数位

6.EmailFiled(varchar(254))

7.DateField(date)
	日期字段,日期格式  YYYY-MM-DD,相当于Python中的datetime.date()实例。

8.DateTimeField(datetime)
	日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
	auto_now:每次修改数据的时候都会自动更新当前时间
	auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了

9.BooleanField(Field)(布尔值类型)
	该字段传布尔值(False/True) 数据库里面存0/1

10.TextField(Field)(文本类型)
	该字段可以用来存大段内容(文章、博客...)  没有字数限制
	后面的bbs作业 文章字段用的就是TextField


11.FileField(Field)(字符类型)
	upload_to = "/data"
	给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中
	/data/a.txt

12.ForeignKey()()外键

13.OneToOneField()(一对一关系)

14.ManyToManyField()(多对多关系)

ORM还支持自定义字段类型

# 定义char类型

# 字段类内部都继承Field
class MyCharField(models.Field):
    # 字符类型都必须有max_length表示字符长度
    def __init__(self,max_length, *args, **kwargs):
        self.max_length = max_length
        # 调用父类的init方法
        super().__init__(max_length=max_length, *args, **kwargs)  # 一定要是关键字的形式传入

    def db_type(self, connection):
        # 返回真真正的数据类型及各种约束条件
        return 'char(%s)' % self.max_length

# 自定义字段使用
myfield = MyCharField(max_length=16,null=True)  # 可以为空

image

ORM常用字段参数

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)
        - 二进制类型

ORM字段参数

# 外键字段及参数
unique=True
    ForeignKey(unique=True)   等价于   OneToOneField()

 
db_index
    如果db_index=True 则代表着为此字段设置索引
  复习索引是什么?
 答: 加快查询速度

to_field
    设置要关联的表的字段  默认不写关联的就是另外一张的主键字段

on_delete
    当删除关联表中的数据时,当前表与其关联的行的行为。
  """
  django2.X及以上版本 需要你自己指定外键字段的级联更新级联删除
  """
字段参数
null
用于表示某个字段可以为空。

unique
如果设置为unique=True 则该字段在此表中必须是唯一的 。

db_index
如果db_index=True 则代表着为此字段设置索引。

default
为该字段设置默认值。

DateField和DateTimeField
auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。

auto_now
配置上auto_now=True,每次更新数据记录的时候会更新该字段。

关系字段
ForeignKey
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
字段参数
to
设置要关联的表

to_field
设置要关联的表的字段

on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。

models.CASCADE

删除关联数据,与之关联也删除

db_constraint
是否在数据库中创建外键约束,默认为True。

models相关:
1、models.CASCADE
        级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
2、models.SET_NULL
        当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
3、models.PROTECT
        当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
4、models.SET_DEFAULT
        当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
5、models.SET()
        当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
6、models.DO_NOTHING
        什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
其余字段参数
复制代码
def func():
    return 10

class MyModel(models.Model):
    user = models.ForeignKey(
        to="User",
        to_field="id",
        on_delete=models.SET(func)
    )
复制代码
OneToOneField
一对一字段。

通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)

字段参数
to
设置要关联的表。

to_field
设置要关联的字段。

on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)

Ajax

我们知道,前端页面想要和后端进行数据交互,可以通过以下方式

将参数添加到url中,后端通过get方式从url中获取数据 GET请求

前端页面通过form表单,将数据以get或者post的方式发送给后端 POST请求/GET请求

前端通过a标签(和使用url方式参数的方式) GET请求

1.什么是Ajax

1.AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

2.Ajax不是新的编程语言,而是一种使用现有标准的新方法。其实就是js自带的功能 我们学习的是jQuery封装之后版本

2.Ajax的优点

1.Ajax最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

2.Ajax不需要任何浏览器插件,但需要用户允许javaScript在浏览器上执行。

同步交互: 客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求。
异步交互: 客户端发出一个请求后,无需要等待服务器响应结束,就可以发出第二个请求。
Ajax用于"局部刷新页面"和"异步提交"的特点

异步提交: 提交完认为不需要原地等待,立马就做其他事
局部刷新: 不在局限于整个页面的刷新,而是在于局部的某一个页面的小块刷新
因此和使用Form表单和后端进行数据交互的方式比较,具有以下优点:

1.Ajax使用JavaScript技术向服务器发送异步请求
2.Ajax请求无须刷新整个页面

因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以Ajax性能高!

3.Ajax工作原理

1.Ajax相当于在用户和服务器之间加了一个中间层(Ajax引擎),使用户操作与服务器响应异步化。

2.并不是所有用户请求都是提交给服务器,像一些数据验证和数据处理等都交给Ajax引擎自己来做,只有确定需要从服务器读取数据时再由Ajax引擎代为向服务器提交请求。

3.客户端发送请求,请求交给Ajax,Ajax把请求提交给服务器,服务器进行业务处理,服务器响应数据交给Ajax对象,Ajax对象接收数据,由JavaScript把数据写到页面上。
要完整实现一个Ajax异步调用和局部刷新,同窗需要以下几个步骤:

1.创建XMLHttpRequest对象,既创建一个异步调用对象
2.创建一个新的HTTP请求,并指定该HTTP请求的方法,URL及验证信息
3.设置响应HTTP请求状态变化的函数
4.发送HTTP请求
5.获取异步调用返回数据
6.使用JavaSciript和DOM实现局部刷新

注意:
Ajax传输数据为XML(当然,传输数据不只是XML,现在更多使用json数据,基本上web页面都是Ajax)

4.基本语法

$.ajax({
	// 发送地址 1.不写默认朝当前所在url提交数据 
	// 2.全写 指名道姓 https://www.baidu.com 
	// 3.只写后缀/login/
	url: '',  
	type: 'get/post',  	// 请求方式 默认get  
	data: {'username':'jason', 'password':123}  //   要发送的数据
	success:function(args){
		// 回调函数(异步回调机制)
	}
})


解析(重要):
    1.当你在利用ajax进行前后端交互的时候
    2.当后端给你返回结果的时候会自动触发 args接受后端的返回结果

小练习

<body>
<form action="" method="post">
    <input type="text" id="d1">+ <input type="text" id="d2">= <input type="text" id="d3">
    <input type="button" value="计算" id="subBtn">
    <script>
        $('#subBtn').click(function (){
            // 超后端发送数据 使用ajax
            $.ajax({
                url:'', // 等价于form表单的action参数
                type:'post',  //等价于form表单的method参数
                data:{'i1':$('#d1').val(),'i2':$('#d2').val()},  //要发送后端的数据
                success:function (args){ // args就是异步提交以后,后端返回的结果
                    $('#d3').val(args)
                }
            })
        })
    </script>
</form>
</body>
def abAjax(request):
    if request.method == 'POST':
        i1 = request.POST.get('i1')
        i2 = request.POST.get('i2')
        res = int(i1) + int(i2)
        return HttpResponse(res)
    return render(request, 'abAjax.html')

image

5.数据编码格式

Content-Type:它会提前告诉后端,接下来的数据到底是什么格式,它会识别到不同的类型分配到不同的编码中
    格式1:urlencoded
        数据格式: name=jason&pwd=123&hobby=read
        django后端统一处理到request.POST中
    格式2:formdata
       数据格式: 无法查阅
       django后端自动将文件数据处理到request.FILES 普通数据request.POST
    格式3:application/json
       数据格式: json格式
            django后端不会处理 在request.body中存储(bytes类型) 自己处理
       语法注意事项
            data: JSON.stringify({'name':'jason','pwd':123}),
            contentType:'application/json',

image

向django发送请求以后,所携带的数据它会放在request.body中,然后识别是什么编码
如果是urlencoded编码,它会将数据解码给request.POST
如果是formdata那么它会解码以后交给request.FILES
那么现在的数据是JSON格式,争对JSON格式没有一个编码进行比对,所以没人管它

那么只能自己处理,

print(request.body)
json_bytes = request.body
import json
json_bytes = json.loads(json_bytes)
print(json_bytes)
"""
b'{"name":"jason","pwd":123}'
{'name': 'jason', 'pwd': 123}
"""

6.Ajax携带数据

$('#d3').click(function () {
        // 1.产生内置对象
        let formData = new FormData();
        // 2.添加普通数据
        formData.append('username',$('#d1').val())
        // 3.添加文件数据
        formData.append('file', $('#d2')[0].files[0])
        // 4.发送ajax请求
        $.ajax({
            url:'',
            type:'post',
            data:formData,
            contentType:false,  // 不使用任何编码
            processData:false,  // 不处理数据对象
            success:function (args) {
            }
        })
    })

image

标签:models,res,price,Django7,查询,Ajax,print
From: https://www.cnblogs.com/zjl248/p/16993127.html

相关文章

  • django7
    图书管理系统讲解1.表设计 先考虑普通字段再考虑外键字段 数据库迁移、测试数据录入2.首页展示3.书籍展示4.书籍添加5.书籍编辑 后端如何获取用户想要编辑的数据、......