模型层

前期数据准备

"""
django自带的sqlite3数据库 功能很少 并且针对日期类型不精确

1.数据库正向迁移命令(将类操作映射到表中)
	python3 manage.py makemigrations
  python3 manage.py migrate
2.数据库反向迁移命令(将表映射成类)
	python3 manage.py inspectdb
"""
需求
	我们只想操作orm 不想使用网络请求
  	需要有专门的测试环境
    1.自己搭建
    tests.py文件
    	import os
			if __name__ == "__main__":
    			os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")
    			import django
    			django.setup()
    2.pycharm提供
    	python console

ORM操作关键字

all()			# 查询所有数据		queryset
filter()  # 根据条件筛选数据 多个条件默认是and关系 queryset
first()		# 获取结果集中的第一个元素		 数据对象
last()		# 获取结果集中的最后一个元素		数据对象
values()  # 可以看成是列表套字典				queryset
values_list()  # 可以看成是列表套元组		queryset
exclude()  # 取反操作									queryset
exists()  # 判断结果集是否有值					 布尔值		
distinct()  # 去重										queryset
order_by()  # 排序										queryset
get()		# 直接获取数据对象							数据对象
count()  # 计数												int

create()  # 创建数据
update()  # 批量修改数据
delete()  # 批量删除数据
"""
参数pk的含义:自动定位到当前表的主键字段
参数-的含义:用于排序中的升序与降序
"""

双下划线查询

算术运算

__gt         大于
__lt         小于
__gte        大于等于
__lte        小于等于
    
# 实例 查询年龄大于20的用户
res = models.User.objects.filter(age__gt=20)
print(res)

成员运算

__in

# 实例 查询年龄是18、22、25的用户
res = models.User.objects.filter(age__in=[18, 22, 25])
print(res)

范围查询

__range

# 实例 查询年龄在18到26之间的用户
res = models.User.objects.filter(age__range=[18, 26])  # 包含18和26
print(res)

字符串查询

__contains      区分大小写
__icontains     忽略大小写
   
# 实例 查询姓名中包含字母j的用户
res = models.User.objects.filter(name__contains='j')
res = models.User.objects.filter(name__icontains='j')
print(res)

时间查询

__year          按照年份筛选数据
__month         按照月份筛选数据
...

# 实例
# 查询月份是5月的数据
res = models.User.objects.filter(op_time__month=5)
print(res)
# 查询年份是22年的数据
res = models.User.objects.filter(op_time__year=2022)
print(res)

其他方法

__startswith # 以...开头
__endswith # 以...结尾
__regex # 正则

外键字段的创建

关系的种类
	一对多关系
	多对多关系
	一对一关系
关系的判断
	换位思考
字段的位置
	一对多关系 外键字段建在多的一方
	多对多关系 外键字段建在第三张关系表中
	一对一关系 外键字段建在任意一方都可以 但是推荐建在查询频率较高的表中

一对多关系

# ForeignKey
'''django orm外键字段针对一对多关系也是建在多的一方 '''
res = models.ForeignKey(to='关联表名')

多对多关系

# ManyToManyField
'''django orm外键字段针对多对多关系 可以不用自己创建第三张表'''
res = models.ManyToManyField(to='关联表名') # res为虚拟字段

一对一关系

# OneToOneField
'''django orm外键字段针对一对一关系 建在查询频率较高的表中'''
res = models.OneToOneField(to='关联表名')

补充

1.ManyToManyField不会在表中创建实际的字段,而是告诉django orm自动创建第三张关系表

2.ForeignKey、OneToOneField会在字段的后面自动添加_id后缀,如果你在定义模型类的时候自己添加了该后缀,那么迁移的时候还会再次添加,_id_id,所以不要自己加_id后缀

3.to用于指定跟哪张表有关系 自动关联主键
to_field\to_fields  也可以自己指定关联字段

外键字段操作

一对多、一对一外键字段操作

1.
models.Book.objects.create(title='聊斋志异', price=16987.22, publish_id=1) # 直接填写关联数据的主键值

2.
publish_obj = models.Publish.objects.filter(pk=2).first() # 先获取一个被关联表的主键对象
models.Book.objects.create(title='资本论', price=56777.98, publish=publish_obj) # 然后在创建外键所在表的记录时,用对象代替关联数据的主键值

1.
models.Book.objects.filter(pk=1).update(publish_id=3) # 直接修改关联数据的主键值

2.
publish_obj = models.Publish.objects.filter(pk=2).first() # 先获取一个被关联表的主键对象
models.Book.objects.filter(pk=1).update(publish=publish_obj) # 用该对象代替关联数据的主键值

多对多字段操作

1.第三张关系表创建数据
book_obj = models.Book.objects.filter(pk=1).first() # 获得一个对象
book_obj.虚拟字段.add() # 虚拟字段 = models.ManyToManyField(to='关联表名')
'括号内可以放主键值也可以放数据对象,并且都支持多个'

2.第三张关系表修改数据
book_obj = models.Book.objects.filter(pk=1).first() # 获得一个对象
book_obj.虚拟字段.set()
'括号内必须是一个可迭代对象,元素同样支持主键值或者数据对象'

3.第三张关系表删除数据
book_obj = models.Book.objects.filter(pk=1).first() # 获得一个对象
book_obj.虚拟字段.remove()
'括号内可以放主键值也可以放数据对象 并且都支持多个'

清空

4.第三张关系表清空指定数据
book_obj = models.Book.objects.filter(pk=1).first() # 获得一个对象
book_obj.虚拟字段.clear() # 该对象在第三张关系表中的绑定记录全部清空
'括号内无需传值 直接清空当前表在第三张关系表中的绑定记录'

多表查询

MySQL多表查询思路
子查询:将SQL语句用括号括起来当做条件使用
连表操作:inner join\left join\right join\union
django orm多表查询思路(本质还是使用的上述两种方法):
子查询:基于对象的跨表查询
连表操作:基于双下划线的跨表查询

正反向的概念

核心在于当前数据对象是否含有外键字段 有则是正向 没有则是反向
正向:
      由书籍查询出版社 外键字段在书籍表中 那么书查出版社就是'正向'
      由书籍查询作者 外键字段在书籍表中 那么书查作者就是'正向'
      由作者查询作者详情 外键字段在作者表中 那么也是'正向'
反向:
      由出版社查询书籍 外键字段不在出版社表 那么出版社查书就是'反向'
"""
查询口诀
正向查询按外键字段名
反向查询按表名小写
"""

基于对象的跨表查询

1.获取已知对象
2.使用跨表查询
3.得到查询对象

# 实例 查询数据分析书籍对应的出版社
    # 先获取书籍对象
    book_obj = models.Book.objects.filter(title='数据分析').first()
    # 再使用跨表查询
    res = book_obj.publish # 正向查询按外键字段名
    print(res)  # 得到一个出版社对象
    
# 实例 查询东方出版社出版的书籍
    publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    res = publish_obj.book_set  # app01.Book.None
    res = publish_obj.book_set.all() # 反向查询按表名小写
    print(res)  

基于双下划线的跨表查询

基于双下划线的跨表查询本质就是连表操作

1.手上有什么条件就先拿models点该条件对应的表名
2.values('关联表名__字段名' ,'关联表名__关联表名__字段名',),可以多个参数 并且关联表可以不断延续

# 实例 查询数据分析书籍对应的价格和出版日期
models.Book.objects.filter(title='数据分析').values('price','publish_time')

# 实例 查询作者jason的手机号和地址
res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')

双下划线查询扩展

基于双下划线的跨表查询的结果也可以是完整的数据对象

1.手上有条件所在的表可以不被models点 直接点最终的目标数据对应的表
2.filter(条件所在表名__字段名='XXX') 关联表可以不断延续
3.获取到一个对象

# 实例 查询数据分析书籍对应的出版社名称
	1.获取对象
	res = models.Publish.objects.filter(book__title='数据分析')
	print(res)  # <QuerySet [<Publish: 出版社对象:北方出版社>]>
    
	2.获取属性
	res = models.Publish.objects.filter(book__title='数据分析').values('name')
	print(res)  # <QuerySet [{'name': '北方出版社'}]>
    
'''连续跨表操作'''
# 实例 查询python全栈开发对应的作者的手机号
res1 = models.AuthorDetail.objects.filter(author__book__title='python全栈开发').values('phone')
print(res1)

如何查看SQL语句

方式1:如果结果集对象是queryset 那么可以直接点query查看
	res = models.Publish.objects.filter(book__title='数据分析')
	print(res.query)
方式2:配置文件固定配置
 	LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
  	适用面更广 只要执行了orm操作 都会打印内部SQL语句

聚合查询

aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

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

# 实例 
res = models.Book.objects.aggregate(Max('price'),
                                    Min('price'),
                                    Sum('price'),
                                    Avg('price'),
                                    Count('pk')
                                    )

print(res)
{'price__max': Decimal('56777.98'), 'price__min': Decimal('16987.22'), 'price__sum': Decimal('179408.51'), 'price__avg': 29901.418333, 'pk__count': 6}

分组查询

ORM使用annotate()执行分组操作,如果报错,可能需要去修改sql_mode,移除only_full_group_by

# 实例
# 统计每本书的作者个数
from django.db.models import Max, Min, Sum, Avg, Count
res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')

# 统计每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')


"""上述操作都是以表为单位做分组 如果想要以表中的某个字段分组如何操作"""
# 统计每个出版社主键值对应的书籍个数
res = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
    print(res)
posted @ 2022-05-17 00:19  Rain_Kz  阅读(26)  评论(0)    收藏  举报