Django ORM 高级操作

Django ORM 高级操作

  • 补充: Django框架中只要是跟数据库相关的模块基本都在django.db.models 中,如果没有就应该在django.db里面

聚合查询

聚合查询(aggregate)通常情况下都是配合分组一起使用的

使用方式:
1. 导入模块
	from django.db.models import Max,Min,Sum,Count,Avg  
    
2. 使用格式
	models.表名.objects.aggregate(函数1('字段名'),函数1('字段名')...)
    
eg: 
    modles.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price'))

分组查询

mysql分组查询特点:

  • 在5.7及以上版本,分组查询默认只能直接获取分组字段信息,组内其他字段都无法直接获取
  • 5.6 版本需要设置严格模式(ONLY_FULL_GROUP_BY)
ROM分组语法:
    models.表名.objects.annotate()    
    注意:  models点什么表名就默认按照什么分组
案例:
    1.统计每一本书的作者个数    			  
    models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')author_num是我们自己定义的字段 用来存储统计出来的每本书对应的作者个数
	可以自定义字段用来配合聚合函数使用  author_num是我们自己定义的字段 
    
按照指定字段分组处理语法:
    models.Book.objects.values('字段').annotate()
    'annotate 前面加了values 就会按照values内指定字段分组'

在这里插入图片描述

F与Q查询

  • F查询(进行表内字段的比较)
F查询能够直接获取表中某个字段对应的数据
语法:
    from django.db.models import F
    1. 查询Book表中kucun大于maichu的数据
    models.Book.objects.filter(kucun__gt=F('maichu'))
    2. 将所有书籍的价格提升500块
    models.Book.objects.update(price=F('price')+500)
    '''
    F 查询可以操作数值型数据运算,但是在操作字符类型的数据的时候 不能够直接做到字符串拼接
    '''
    from django.db.models.functions import Concat
    from django.db.models import Value
    # Concat配合Value 就可以用来进行字符类型数据拼接,执行不会报错但是数据会变成空白
    models.Book.objects.update(title=Concat(F('title'),Value('xxx')))
  • Q查询
由于filter括号内多个参数是and关系,没有其他关系(or not)
from django.db.models import Q
这个时候就需要Q查询
modles.Book.objects.filter(Q(maichu_gt=100),Q(price_lt=600))  # 默认还是and关系 ,
modles.Book.objects.filter(Q(maichu_gt=100)|Q(price_lt=600))  # or关系 |
modles.Book.objects.filter(~Q(maichu_gt=100)|~Q(price_lt=600))  # not ~


Q 的高阶用法 够将查询条件的左边也变成字符串的形式

q = Q()
q.connector = 'or'  # 修改关系

q.children.append(('maichu__gt',100))
q.children.append(('price__lt',600))
models.Book.objects.filter(q)  # 默认还是and关系

Django开启事务

事务: ACID 四个特性 原子性,一致性,隔离性,持久性

from django.db import transaction

with transaction.atomic(): # 开启事务
    sql1
    sql2
    ...
    # 在with代码块内书写的所有orm操作都是属于同一个事务  

在这里插入图片描述

ORM中常用参数

AutoField
	主键字段 primary_key=True
  
CharField				varchar
	verbose_name	字段的注释
  max_length		长度
  
IntegerField			int
BigIntegerField		bigint

DecimalField
	max_digits=8
  decimal_places=2

EmailFiled				varchar(254)

DateField					date
DateTimeField			datetime
	auto_now:每次修改数据的时候都会自动更新当前时间
  auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了
    
BooleanField(Field)				- 布尔值类型
	该字段传布尔值(False/True) 	数据库里面存0/1

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


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

# 更多字段
直接参考博客:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
  • 自定义字段
# django除了给你提供了很多字段类型之外 还支持你自定义字段
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
    
    
  • 外键字段及参数
unique=True
	ForeignKey(unique=True)   ===			OneToOneField()
  #  你在用前面字段创建一对一 orm会有一个提示信息 orm推荐你使用后者但是前者也能用
  
db_index
	如果db_index=True 则代表着为此字段设置索引


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

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

在这里插入图片描述

数据库查询优化

ORM语句特点(惰性查询):

  • 如果仅仅书写了orm语句,在后面如果没有用到该语句所查询出来的参数,那么orm会自动识别 直接不执行
  • 数据库优化两队参数(only与defer)和(select_related与prefetch_related)

only与defer

only作用: 只获取指定字段的数据
    modles.表名.objects.only('字段名')
defer作用: 获取指定字段之外的数据
    modles.表名.objects.defer('title')
    
注意:
    使用only获取的quertser对象同样可以获取其他字段数据,不过需要重新在数据库中查询
    defer括号内放的字段不在查询出来的对象里面 查询该字段需要重新走数据
        而如果查询的是非括号内的字段 则不需要走数据库了   

select_related与prefetch_related

select_related 可以看做是 INNER JOIN
	可以通过外键字段将两张表连起来,然后一次性将大表里面的所有数据全部封装起来给查询出的对象,这个时候查询两张表内的数据都无需再走数据库。
    注意: select_related 括号内只能放外键字段   只支持一对多和一对一关系表使用
        
prefetch_related 可以看成是  子查询       
	prefetch_related内部就是子查询
    	会将子查询查询出来的结果(默认是按照外键字段查询)封装到对象中

choice参数

  • choice参数是数据库字段设计中十分常见的一个字段
  • 该字段可以针对某个可以列举完全的可能性字段的存储方式
  • 只要某个字段的可能性是可以列举完全的,那么一般情况下都会采用choices参数
class User(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField()
    # 性别
    gender_choices = (
        (1,'男'),
        (2,'女'),
        (3,'其他'),
    )
    # 保证字段类型和对应choices内元组第一个参数一致
    gender = models.IntegerField(choices=gender_choices):	# 存的时候 正常存即可,即使不在列举出来的范围内的数据也能存储(前提:在字段类型内)
     models.User.objects.create(username='jason',age=18,gender=1)
     models.User.objects.create(username='tony',age=45,gender=4):
    user_obj = models.User.objects.filter(pk=1).first()
    # 只要是choices参数的字段 如果你想获取对应信息 固定写法 get_字段名_display()
    print(user_obj.get_gender_display())  # 男
    
    # 取的时候,如果没有对应关系,那么字段值是什么就还是展示什么
    user_obj = models.User.objects.filter(pk=2).first()
    print(user_obj.get_gender_display())  # 4	

MTV与MVC模型

1. MTV : Django专属MTV模型
    M:models  (模型层:跟数据相关)
    T:templates (模板层:html页面)
    V:views     (逻辑层:代码逻辑相关)
            
2. MVC : 其他语言,Django本质上也是MVC
    M : model (数据处理层)
    V : Views (视图页面层)
    C : controller (控制器,主要写逻辑)
    S : service (服务处,大型项目中抽象出的第四层)     

多对多三种创建方式

1. 全自动
	class Book(models.Model):
    	name = models.CharField(max_length=32)
    	authors = models.ManyToManyField(to='Author')
	class Author(models.Model):
   		name = models.CharField(max_length=32)
'''
	优点: 不需要手动创建第三张表,支持orm提供操作第三张关系表的方法
	缺点: 第三张表的扩展性极差,没有办法额外添加字段
'''        
2. 纯手动
	class Book(models.Model):
        name = models.CharField(max_length=32)
        
	class Author(models.Model):
        name = models.CharField(max_length=32)
        
	class BooktoAuthor(models.Model):
        book_id = models.ForeignKey(to='Book')
        author_id = models.ForeignKey(to='Author')
'''
	优点: 第三张表完全取决于你自己进行的额外的扩展
	缺点: 代码加多,不能够使用orm提供的简单方法(不推荐使用)
'''        
3. 半自动
	class Book(models.Model):
    	name = models.CharField(max_length=32)
    	authors = models.ManyToManyField(to='Author',
                                        through='Book2Author',
                                        througn_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')   
        
'''
	through: 指定第三张表
	through_fields字段先后顺序
		判断的本质:
			通过第三张表查询对应的表,需要那个字段就把那个字段放在前面
		简化:
        	当前表是谁 就把对应的关联字段放在前面
        	
	优点: 可以使用orm的正反向查询,第三张表的可扩展性强
	缺点: 代码多了 , 没法使用add,set,remove,clear这四个方法
'''

总结:
    三种多对多的方法,需要掌握全自动和半自动,为了可扩展性更高  推荐使用半自动
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值