Django微讲解(七)

Django微讲解(七)

聚合查询

	我们在讲数据库的聚合查询的时候,讲了数据库的聚合函数,常用就是最大值'max'、最小值'min'、求和'sum'、计数'count'、
平均值'avg',我们的Django ORM聚合查询使用的也是这些关键字,只不过数据库的聚合函数是需要分组之后才可以使用的,而Django ORM
的聚合函数没有分组也可以使用聚合函数,默认整体的一个表就是一组。
    from django.db.models import Max,Min,Count,Sum,Avg
    res = models.Book.objects.aggregate(Max('price'))
    print(res)
    使用聚合查询的关键字是'aggregate'

分组查询

	数据库的分组查询使用的是group by关键字,Django ORM使用的关键字是'annotate',ORM在执行分组操作的时候,有的计算机
会报错,报错的话可以去修改'sql_mode',移除'only_full_group_by'即可。
# 1.统计每本书的作者个数
	res = models.Book.objects.annotate(auhtor_num=Count('authors__pk')).values('title','auhtor_num')
    print(res)
# 2.统计每个出版社卖的最便宜的书的价格
    res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    print(res)
# 3.统计不止一个作者的图书
    res = models.Book.objects.annotate(author_count=Count('authors__pk')).filter(author_count__gte=2).values('title','author_count')
    print(res)
# 4.统计每个作者出的书的总价格
	res = models.Author.objects.annotate(price_num=Sum('book__price')).values('name','price_num')
    print(res)
# 5.统计每个出版社主键值对应的书籍个数
'''
上述四个练习题都是以表为单位分组的,如果想要以表中的某个字段分组,只需要在'annotate'关键字前面点'values'给某个字段进行分组即可
'''
	res = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
    print(res)

往已经存在数据的表中添加字段

    当表中已经存在数据的情况下,想要在添加额外字段,就需要指定该字段的默认值,或者指定该字段的值可以为null
    方式一:
		可以给额外添加的字段加一个默认值,关键字是'default'
        示例:age = models.IntegerField(default=25)
	方式二:
        设置额外添加字段的值可以为null
        示例:age = models.IntegerField(null=True)
	方式三:
        可以在迁移命令的提示中直接给默认值

F查询

	 F可以帮我们取到表中某个字段对应的值来当做我们的筛选条件,而不是自定义常量的条件,实现了动态比较的效果,Django还支
持F对象之间以及F对象与常数之间的加减乘除和取模的操作。
# 1.查询库存大于销量的书籍
	from django.db.models import F
	res = models.Book.objects.filter(kucun__gt=F('xiaoliang'))
	print(res)
# 2.将所有书的价格提升1000块
    res = models.Book.objects.update(price=F('price') + 1000)
    print(res)
# 3.将所有书的名称后面加上_爆款后缀
'''
想要修改char字段的值,不可以用上述的方法,可以使用下面ORM专门提供的方法
'''
	from django.db.models.functions import Concat
    from django.db.models import Value,F
    models.Book.objects.update(title=Concat(F('title'),Value('_iii')))

Q查询

	filter()方法中逗号隔开的条件是'and'的关系,是没有办法直接修改的,所以我们就可以使用Q对象,支持逻辑运算符,'管道
符'(|)就是'or'关系,在Q对象前面加'~'就是'not'的关系。
# 1.查询价格大于20000或者卖出大于1000的书籍
	from django.db.models import Q
    res = models.Book.objects.filter(Q(price__gt=20000)|Q(xiaoliang__gt=1000))
    print(res)  # 管道符是or关系
# 2.查询价格小于20000或者库存小于1000的书籍
	res = models.Book.objects.filter(~Q(price__gte=20000)|~Q(kucun__gte=1000))
    print(res)  # ~是not关系
# 3.Q对象进阶用法
	q_obj = Q()  # Q方法其实是一个类,我们先产生一个q_obj对象
    q_obj.connector = 'or'  # 默认是and关系,可以改没or
    q_obj.children.append(('price__gt',20000))
    q_obj.children.append(('kucun__gt',1000))
    res = models.Book.objects.filter(q_obj)
    print(res)

ORM查询优化

	ORM查询默认都是惰性查询,能不消耗数据库资源就不消耗,ORM查询默认自带分页功能,尽量减轻单次查询数据的压力
# only
	only会产生对象结果集,对象点括号内出现的字段不会再次查询数据库
    res = models.Book.objects.only('title','price')
    for obj in res:
        print(obj.title)
        print(obj.price)
        # print(obj.xiaoliang)  # 也可以点括号以外的,但是会再次查询数据库,增加了数据库的压力
# defer
	defer也会产生对象结果集,对象点括号之外的字段不会再次查询数据库
    res = models.Book.objects.defer('title','price')
    for obj in res:
        print(obj.xiaoliang)
        # print(obj.price)  # 也可以点括号内的,但是会再次查询数据库,增加数据库的压力
# select_related
	select_related括号内只能传外键字段,只能传一对一和一对多字段,不能传多对多字段,内部原理就是直接连表,然后将连
接之后的表中所有的数据全部封装到数据对象中,然后对象就可以通过正反向查询,内部不会再次查询数据库,不会增加数据库的压力。
    res = models.Book.objects.select_related('publish')
    for obj in res:
        print(obj.title)
        print(obj.price)
        print(obj.publish.name)
        print(obj.publish.addr)
# prefetch_related
	prefetch_related括号内只能传外键字段,只能传一对一和一对多字段,不能传多对多字段,内部原理是将多次查询之后的结
果封装到数据对象当中,然后对象就可以通过正反向查询,内部不会再次查询数据库,不会增加数据库的压力。
    res = models.Book.objects.prefetch_related('publish')
    for obj in res:
        print(obj.title)
        print(obj.price)
        print(obj.publish.name)
        print(obj.publish.addr)

ORM常见字段

# 1.AutoField
	int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
# 2.IntegerField
	整型int
# 3.CharField
	字符类型,必须提供max_length参数, max_length表示字符长度,对应的是数据库中的varchar类型,没有设置对应char类型
的字段,但是Django允许我们自定义新的字段。
# 4.DecimalField
	10进制小数
# 5.DateField
	日期字段,日期格式  YYYY-MM-DD,相当于Python中的datetime.date()实例。
# 6.DateTimeField
	日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
# 7.BigIntergerField
	整型bigint
# 8.BooleanField
	传布尔值,对应的是0和1
# 9.TextField
	存储大段文本
# 10.FileField
	传文件自动保存到指定位置并存文件路径
# 11.EmailField
	本质还是varchar类型 

ORM重要参数

# 1.primary_key
	主键
# 2.max_length
	字段最大长度
# 3.verbose_name
	注释
# 4.null
	是否允许为空
# 5.default
	设置默认值
# 6.max_digits
	小数总长度
# 7.decimal_places
	小数位长度
# 8.unique
	如果设置为unique=True 则该字段在此表中必须是唯一的 。
# 9.db_index
	如果db_index=True 则代表着为此字段设置索引。
# 10.auto_now
	配置上auto_now=True,每次更新数据记录的时候会更新该字段。
# 11.auto_now_add
	配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
# 12.choices
	用于可以被例举完全的数据
# 13.to
	设置要关联的表
# 14.to_field
	设置要关联的表的字段
# 15.db_constraint
	是否在数据库中创建外键约束,默认为True。
'''
外键字段中使用related_name参数可以修改正向查询的字段名
'''
choices示例:
    models.py文件:
        class Info(models.Model):
            username = models.CharField(max_length=255)
            password = models.IntegerField()
            gender_choies = (
                (1,'nan'),
                (2,'nv'),
                (3,'bian')
            )
            gender = models.IntegerField(choices=gender_choies)
    test.py文件:
        res = models.Info.objects.filter(pk=1).first()
    	print(res.get_gender_display())

事务操作

# MySQL事务四大特性
	原子性、一致性、持久性、独立性
# MySQL事务的关键字
	开启事务:start transcation
	事务回滚:rollback
	确认事务:commit
# ORM事务操作
	from django.db import transaction
    try:
        with transaction.atomic():  # with语句结束,事务结束
            pass  # 事务代码
    except Exception:
        pass

ORM执行原生SQL

# 方式1
from django.db import connection, connections
cursor = connection.cursor()  
cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
cursor.fetchone()

# 方式2
models.UserInfo.objects.extra(
                    select={'newid':'select count(1) from app01_usertype where id>%s'},
                    select_params=[1,],
                    where = ['age>%s'],
                    params=[18,],
                    order_by=['-age'],
                    tables=['app01_usertype']
                )

多对多创建方式

# 1.全自动
	全自动就是ORM自动创建第三张表,但是没有办法扩展第三张表的字段
    示例:authors = models.ManyToManyField(to='Author')
# 2.全手动
	第三张表可以完全自定义,扩展性高,但是不能使用外键方法和正反向查询
    示例:
        class Book(models.Model):
        	title = models.CharField(max_length=32)
       class Author(models.Model):
        	name = models.CharField(max_length=32)
       class Book2Author(models.Model):
            book_id = models.ForeignKey(to='Book')
            author_id = models.ForeignKey(to='Author')
# 3.半自动
	可以使用正反向查询,第三张表还可以扩展,但是不能使用add、set、remove、clear这四种方法
    示例:
'''
多对多建在任意一方都可以,如果建在Author表,字段顺序互换即可
'''
        class Book(models.Model):
            title = models.CharField(max_length=32)
            authors = models.ManyToManyField(
                                    to='Author',
                                    through='Book2Author',  # 指定表
                                    through_fields=('book','author')  # 指定字段
            					)
      class Author(models.Model):
            name = models.CharField(max_length=32)
      class Book2Author(models.Model):
            book = models.ForeignKey(to='Book')
            author = models.ForeignKey(to='Author')

这里是IT小白陆禄绯,欢迎各位大佬的指点!!!

posted @ 2022-05-18 20:01  陆禄绯  阅读(75)  评论(0)    收藏  举报