关于django的ORM的操作

import os
import time

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings")
import django

django.setup()
from app01 import models
  上面的代码是在本地进行orm测试需要添加的

# 单表操作
# 增
# res = models.User.objects.create(name='alex', age=18, register_time='2022-5-17')
# res = models.User.objects.create(name='jason', age=25, register_time='2021-5-17')

# 删除, 方式1
# models.User.objects.filter(pk=1).delete()
# 方式二:
# user_obj = models.User.objects.filter(pk=2).first()
# user_obj.delete()

# 修改 方式一
# models.User.objects.filter(pk=3).update(name='haojiangzhu')
# 方式二
# user_obj = models.User.objects.filter(pk=3).first()
# print(user_obj)
# user_obj.age = 99
# user_obj.save()

# 查
# filter返回的queryset对象, 数据不存在不会报错而是返回None
# get方法返回分时当前数据对象, 数据不存在该方法会直接报错,不建议使用

"""
必知必会十三条
filter() # 带有过滤条件的查询
get() # 直接拿数据对象, 但是条件不存在直接报错
all() # 查询所有数据
first() # 拿queryset里面的第一个对象
last() # 拿queryset里面的最后个对象
values() # 可以获取指定的数据字段 列表套字典
values_list() # 可以回去指定的数据字段 列表套元组
distinct() # 去重, 去重一定是要一模一样的数据, 查询的数据带有主键, 主键都不一样, 就不能去重
order_by() # 排序
reverse() # 结果顺序反转(前提是数据已经排好队)
count() # 计数
exclude() # 排除在外
exists() # 返回的是布尔值,存在True不存在False
"""
# all
# res = models.User.objects.all()
# print(res)

# get
# res = models.User.objects.get(name='alex') # User object
# print(res)

# filter
# res = models.User.objects.filter(name='alex') # <QuerySet [<User: User object>]>
# print(res)

# first
# res = models.User.objects.all().first() # User object
# print(res)

# last
# res = models.User.objects.all().last()

# values
# res = models.User.objects.all().values('name', 'age') # <QuerySet [{'name': 'haojiangzhu', 'age': 99}>
# print(res)

# values_list # <QuerySet [('haojiangzhu', 99), ('alex', 12), ('egon', 13)]>
# res = models.User.objects.all().values_list('name', 'age')
# print(res)

# order_by(默认正序, 加-号为倒序)
# res = models.User.objects.values('name', 'age').order_by('age')
# print(res)

# distinct
# res = models.User.objects.values('name', 'age').distinct()
# print(res)

# reverse()
# res = models.User.objects.values('name', 'age').order_by('age')
# print(res.reverse())

# count()
# res = models.User.objects.count()
# print(res)

# exclude()
# res = models.User.objects.all().values('name', 'age').exclude(name='haojiangzhu')
# print(res)

# exists()
# exists = models.User.objects.filter(name='haojiangzhu').exists()
# if exists:
# print('优质')

# 双下划线查询
# 大于, 年龄大于35岁的数据 gt
# res = models.User.objects.filter(age__gt=35).values('name', 'age')
# print(res)

# 小于, 年龄小于35岁的数据lt
# res = models.User.objects.filter(age__lt=35).values('name', 'age')
# print(res)

# 大于等于 gte 小于等于 lte

# 或, 年龄是18 或 32 或40 in
# res = models.User.objects.filter(age__in=[18, 32, 40]).values('name', 'age')
# print(res)

# 年龄在18-40 range
# res = models.User.objects.filter(age__range=[18, 40])
# print(res)

# 模糊查询, 查询出名字里含有s的数据contains(区分大小写)
# res = models.User.objects.filter(name__contains='z').values('name', 'age')
# print(res)

# 模糊查询, 忽略大小写icontains

# 以什么开头startswith
# res = models.User.objects.filter(name__startswith='h')

# 以什么结尾endswith
# res = models.User.objects.filter(name__endswith='u')

# 查询时间__month月 __year年
# res = models.User.objects.filter(register_time__month='1')

# res = models.User.objects.filter(register_time__year='2020')

# 一对多外键增删改查
# 增
# 1. 直接写实际字段publish_id = 1
# models.Book.objects.create(name='你真好', price=123, publish_id=1)
# models.Book.objects.create(name='三国演义', price=444, publish_id=2)
# models.Book.objects.create(name='水浒传', price=555, publish_id=3)
# 2. 写虚拟字段 = 对象 传对象
# publish_obj = models.Publisher.objects.filter(pk=3).first()
# models.Book.objects.create(name='呐喊', price=666, publish=publish_obj)

# 删除
# models.Book.objects.filter(name='你真好').delete()

# 改
# models.Book.objects.filter(name='呐喊').update(price='69.9')

# 多对多外键增删改查
# 给书籍添加作者, 可以使用数字, 也可以使用对象
# 给地第三张关系表添加数据可以是数字和对象
# book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.add(1, 4)

# author_obj = models.Author.objects.filter(pk=3).first()
# book_obj.authors.add(author_obj)

# 删除 remove()括号内既可以传数字也可以传对象, 支持多个
# book_obj = models.Book.objects.filter(pk=4).first()
# book_obj.authors.remove(1)

# 改 set 括号内需要传递可迭代对象,支持多个, 对象内既可以是数字也可以是对象
# book_obj = models.Book.objects.filter(pk=4).first()
# book_obj.authors.set([1, 2])

# 清空 clear() 括号内不要加任何参数
# 在第三张表中清空某个书籍与作者的关系

# book_obj.authors.clear()

# 正向查询按字段, 反向查询按表名小写

# 多表查询
# 子查询(基于对象的跨表查询)
# 正向
# 1.查询书籍主键为2的出版社
# book_obj = models.Book.objects.filter(pk=2).first()
# res = book_obj.publish.name
# print(res)
# 反向
# publish_obj = models.Publisher.objects.filter(book__pk=2).first()
# print(publish_obj.name)
# 2.查询书籍主键为2的作者
# book_obj = models.Book.objects.filter(pk=2).first()
# res = book_obj.authors.all()
# print(res)

# 3.查询作者jason的电话号码
# author_obj = models.Author.objects.filter(name='jason').first()
# res = author_obj.author_details # AuthorDetail表对象
# print(res.phone)

"""
结论:
如果查询结果为多个的需要加上.all()方法
为单个的不需要, 直接拿数据对象
"""
# 反向(反向用表名小写)
# 4.查询出版社是东方出版社出版的书
# publish_obj = models.Publisher.objects.filter(name='清华出版社').first()
# res = publish_obj.book_set # app01.Book.None
# 查询结果为多个需要加上.all()
# res = publish_obj.book_set.all()
# print(res)

# 5.查询作者是jason写过的书
# author_obj = models.Author.objects.filter(name='jason').first()
# res = author_obj.book_set.all()
# print(res)

# 6.查询手机号是110的作者姓名
# author_detail_obj = models.AuthorDetail.objects.filter(phone='123213213').first()
# res = author_detail_obj.author
# print(res.name)

"""
总结: 反向查询时:
当查询结果有多个是需要加上_set.all(), 返回queryset对象
查询结果为单个的时候不需要加, 直接返回对象
"""

# 联表查询(基于双下划线的跨表查询)
# 1.查询jason的手机号和作者姓名
# 正向
# res = models.Author.objects.filter(name='jason').values('author_details__phone', 'name')
# print(res)
# 反向基于AuthorDetail表查询
# res = models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__name')
# print(res)

# 2.查询书籍主键为2的出版社名称和书的名称
# 正向
# res = models.Book.objects.filter(pk=2).values('publish__name', 'name')
# print(res)
# 反向
# res = models.Publisher.objects.filter(book__pk=2).values('name', 'book__name')
# print(res)

# 3.查询书籍主键为2的作者姓名
# 正向
# res = models.Book.objects.filter(pk=2).values('authors__name')
# print(res)
# 反向
# res = models.Author.objects.filter(book__pk=2).values('name') # 拿写了书籍pk=2的作者详情
# print(res)
# 4.查询书籍主键是2的作者的手机号
# 正向
# res = models.Book.objects.filter(pk=2).values('authors__author_details__phone') # 书籍>作者>作者详情
# print(res)

# 反向
# res = models.Author.objects.filter(book__pk=2).values('author_details__phone')
# print(res)

# 聚合查询 aggregate
# from django.db.models import Max, Min, Count, Sum, Avg
#
# # 上诉方法一次性使用
# res = models.Book.objects.aggregate(Max('price'), Min('price'), Count('pk'), Sum('price'), Avg('price'))
# print(res)

# 分组查询 annotate
from django.db.models import Max, Min, Count, Sum, Avg

# # 1. 统计每一本书的作者个数
# res = models.Book.objects.annotate(author_sum=Count('authors')).values('name', 'author_sum')
# print(res)
'''
author_sum是自定义的字段, 用来统计作者的个数
'''
# 2.统计每个出版社卖的最便宜的书的价格
# res = models.Publisher.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
# print(res)

# 3.统计不止一个作者的图书
# res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('name', 'author_num')
# print(res)
"""
只要你的orm语句得出的结果还是queryset对象
name他就可以继续无限制的点queryset方法
"""
# 4.查询每个作者出的书的总价格
# res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
# print(res)

"""
按照指定字段分组
models.Book.objects.values(字段).annotate()
"""

# F 与 Q查询
# F查询: 能够帮你直接获取表中某个字段的对应的数据
from django.db.models import F, Q

# 1. 查询销售额大于库存的书籍
# res = models.Book.objects.filter(sales__gt=F('store')).values('name', 'sales', 'store')
# print(res)
# print(type(F('store')))

# 2,将所有书籍价格提升500块
# res = models.Book.objects.update(price=F('price')+500)
# print(res)

# 3.将所有数的名称后面加上爆款
"""
在操作字符类型的数据的时候, F不能直接做字符串的拼接
"""
# from django.db.models.functions import Concat
# from django.db.models import Value
#
# models.Book.objects.update(name=Concat(F('name'), Value('(爆款)')))

# Q查询 (逗号, 和), (| 或), (~ 非)
# 1.查询卖出数大于100或者价格小于600的书籍
# res = models.Book.objects.filter(Q(sales__gt=100)|Q(price__lt=600)).values('name', 'price', 'sales')
# print(res)

# Q的高阶用法, 能够将查询条件的左边也变成字符串
# q = Q()
# # 连接方式
# q.connector = 'or' # 默认还是and关系
# q.children.append(('sales__gt', 100))
# q.children.append(('price__lt', 600))
# res = models.Book.objects.filter(q)
# print(res)

# django中如何开启事务
"""
事务的四大特性: ACID
原子性
不可分割的最小单位
一致性
跟原子性相辅相成
隔离性
事务之间互不干扰
持久性
事务一旦确认永久生效
事务的回滚
rollback
事务的确认
commit

"""
# django中如何开启简单的事务
"""
from django.db import transaction
try:
with transaction.atomic():
pass
# spl
# spl
except Exception as e:
print(e)
print('执行其他操作')
"""

# orm中常用字段和参数
"""
AutoField 主键字段 primary_key = True

CharField varchar max_length 长度, verbose_name 字段的注释

IntegerField int

BigIntegerField bigint

DecimalField 浮点数 max_digits 值的总长度 decimal_places小数点后的长度

EmailField varchar(254)

DateField date
DatetimeField datetime
auto_now: 每次修改数据的时候会自动更新当前的时间
auto_now_add: 只在创建数据的时候记录创建时间, 后面不会再自动改变

BooleanField 布尔值类型 数据库里面传0/1(False/True)

TextField 文本类型 没有字数限制, 可以用来存放大文章

FileField 字符类型 upload_to = '/xxx'
给该字段传一个文件对象, 会自动将文件保存到/xxx文件夹下, 然后将文件路径存入数据库

自定义生成字段类型
class MyCharField(models.Field):
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):

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

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


外键字段及参数
ForeignKey(unique=True) === OneToOneField()(推荐使用)

db_index: db_index=True 则代表为该字段设置索引

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

on_delete: 当删除表的时候吗当前表与其关联表的行为

django2.x以上额版本需要自己设置, 1.x默认为级联删除

"""

# 数据库查询优化
# only与defer
# select_related与prefetch_repated
# orm语句的特点, 惰性查询
# 如果你仅仅是指书写了orm语句, 在后面没有使用到查询出来的参数, orm会自动识别 直接不执行

# only与defer
# 想要获取书籍表中所有书的名字
# res = models.Book.objects.values('name')
# for i in res:
# print(i.get('name'))

# res = models.Book.objects.only('name')
# res = models.Book.objects.all()
# for i in res:
# print(i.name) # 获取only括号内的字段不会再查询数据库
# print(i.price) # 获only括号内没有的字段, 会重新走数据库查询, 而all不需要走了

# defer: 与only正好相反, 括号内的需要在查一遍, 括号外的不需要再查一遍
# res = models.Book.objects.defer('price')
# for i in res:
# print(i.name)
# print(i.price)

# select_related与prefetch_related 这两个和跨表操作有关
# res = models.Book.objects.all()
# for i in res:
# print(i.publish.name) # 通过book对象查询出版社对象, 每循环一次都要查询次数据库

# res = models.Book.objects.select_related('publish') # inner join
# print(res)
# for i in res:
# print(i.publish.name)

"""
selected_related内部直接先将book和publisher表连接起来, 将两张表的数据全部封装给查询出来的对象
这是时候无论点击book表中的数据还是publisher表中的数据都不需要再查一遍
"""

# prefetch_related 子查询
# res = models.Book.objects.prefetch_related('publish')
# for i in res:
# print(i.name)

"""
prefetch_related内部就是子查询, 将子查询出来的结果也封装到对象中, 给你的感觉好像是一次性搞定的
"""
posted @ 2022-05-18 15:25  努力搬砖的zh  阅读(31)  评论(0编辑  收藏  举报