首页 > 其他分享 >DjangoORM语法

DjangoORM语法

时间:2023-12-05 23:58:10浏览次数:36  
标签:__ name models DjangoORM 查询 语法 objects 主表

ORM语法-配置

django中与数据库映射的关系,不需要写原始sql语句,而是定义模型类,操作模型完成对数据库进行增删改查等操作。
o 指类对象的意思
r 指数据库表的意思
m 指映射的意思

orm的优点
数据库模型定义在一个地方,方便维护
orm有现成的工具,很多功能自动完成,比如数据库消除,预处理,事务。
orm就是天然的models,使代码更加清晰
基于orm的业务代码比较简单,代码量少,语义性好,容易理解
orm不需要编写复杂的sql语句
开发中应用orm将来如果进行切换数据库,只需要切换orm底层的数据驱动就可以


数据库配置
模型类创建
迁移命令
模型类的命令进行增删改查

1.配置mysql信息
2.创建表结构
3.输入命令,创建表
4.增删改查

数据库的配置

django默认使用的是自带的sqite数据库

使用mysql数据库的
1.安装驱动
pip install pymysql

2.在django中配置数据库设置/settings.py
默认:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

配置为mysql的数据配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST':'127.0.0.1', # mysql的ip地址
        'PORT':'3306', # mysql的端口
        'USER':'root', # mysql的账户
        'PASSWORD':'123', # mysql的密码
        'NAME':'创建数据的名称' # mysql的数据库,在django中创建的表在那个数据库进行存储
    }
}

3.设置django数据的pymysql的驱动模块
import pymysql
pymysql.install_as_MySQLdb()
在全局程序中的init.py文件中设置mysql的驱动

配置2:
# 将ORM操作转换成为 mysql中sql语句
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}


3.还需要在主程序上设置
先在 主程序的文件中 __init__.py文件中设置接口
import  pymysql
pymysql.install_as_MySQLdb()

模型类的声明相关参数

每个程序的下面有一个models.py文件,这个文件存放在数据库的模型类

# 1.设置数据库的名字(不适用默认的)
在创建数据库时,django会使用默认的小写app名+小写的模型类为数据库的名字
可以使用db_table进行指明数据库名

class Mate:
	db_table = '指明的数据库名称'
    
    
# 2.关于表中的主键
id = models.AutoField(primary_key=True) 手动设置主键
如果不设置主键,django会自己生成一个新的主键名为id。
    
    
# 3.关于django模型类的字段类型
AutoField 自增主键字段,primary_key=True设置后就是主键

BooleanField 布尔字段 只有True和False

NullBooleanField 布尔字段,也支持True和False Null

CharField 字符串字段,max_length=对应mysql中varchar类型

TextField 大文本字段,超过4000个字符才使用

IntegerField 整数字段

DecimalField :DecimalField(max_digits=总数位,decimal_places=小数位) 
	例如:
    	DecimalField(max_digits=8,decimal_places=2) 123456.78 # 小数+整数=8
        
FloatField:浮点型小数

DateField:日期类型
	参数:
    	auto_now :每次保持对象时,自动设置的时间
    	auto_now_add :第一次对象保持时自动设置当前时间
        
TimeField:时间类型
	参数:与DateField相同
   
DateTimeField:时间类型
	参数:与DateField相同
 
FileField:上传文件字段,django在文件字段中设置了上传文件保存类,django可以通过模型字段存储自动保存伤处啊文件,但是,在数据库中本质只是存放文件的路径

ImageField: 继承FileField,对上传内容进行校验,确保时有效的照片
    
    
# 4.关于模型类中的约束参数

null : True 表示允许为空,默认为False # 在数据库存储时
blank: True 表示允许为空,默认为False # 在页面进行输入时
db_column : 字段的名称,在数据存储的名字按照db_column的值来定
db_index : 如果时True 在表中创建索引 默认为False,相当于sql中的key
default: 默认值设置,如果填写数据的话,就是该值的为默认值。
primary_key:如果时True,字段变为该表的主键id,不需要设置,系统默认会设置
unique: 如果为True 该字段在表中必须是唯一0,默认是False 相当于sql中唯一索引
    
    
# 5.外键关联参数
在关联外键时,需要通过参数 on_delect选在指明主表删除的数据,对于外键表数据如何处理,在django.db.models中包含的参数
models.CASCADE(): 联级,删除主表数据连同副表一起删除数据
models.PROTECT(): 保护,通过抛出ProtectedError异常,来阻止删除主表被外键应用数据
models.SET_NULL(): 设置为null,仅在字段null=Tuer允许为null
models.SET_DEFAULT(): 设置为默认值时可以使用
models.SET(): 设置为特定值或者特定方法。这个方法就是可以给传入特殊的值

数据库迁移

python manage.py makemigrations # 创建文件,app程序中migrations文件中进行创建文件,并且记录r

python manage.py migrate # 创建表,在mysql中创建表结构,加载django自己内部的表结构

注意:需要注意配置文件中,app已经被注册
settings.py中的INSTALLED_APPS注册是否完成。

指定app程序进行迁移
python manage.py makemigrations 指定那个app
python manage.py migrate

模型类创建

# 每个app下的models.py中进行创建
from django.db import models

class Student(models.Model):
    '''创建一个类'''
    sex_choices = (
        (1, '男'),
        (2, '女'),
        (3, '不男不女')
    )
    # id = models.AutoField(primary_key=True) 手动设置主键
    name = models.CharField(max_length=32, unique=True)  # 字符串类型unique=True名字是唯一的
    age = models.IntegerField(verbose_name='年龄', default=18)  # 整数类型 null=True,可以为空 blank=True 输入可以为空
    sex = models.IntegerField(
        choices=sex_choices, default=1)  # choices参数传入一个元组套元组,将元组中的数值存储数据库,需要取对应的中文,需要别的操作 object.get_level_display()
    birthday = models.DateField()  # 年月日类型 必须是2021-12-12格式 要不然就用 datetime.date(2012,2,2)

    # 默认生产的就是一个 app01_Student 的表名 程序名+创建的表明

    class Meta:
        db_table = 'db_student'  # 使用这个抽象类(元类),重新定义表的名称/不适用原默认名字
   def __str__(self):
        return self.name  # 不显示对象类型信息,显示name文本

models.表名.objects

ORM语法-基本操作

添加

from app01 import models # 导入模型类

1. 方式1 实例化+save(),添加值
sut = models.Student(name='张四',age=22,sex=1,birthday='2012-12-12') # 实例化对象
sut.save() # 生成对应sql语句,添加到数据库中
print(sut.name) # 使用实例化的对象调用对应的字段显示内容
print(sut.age)  
print(sut.sex)

2.方式2  models.Student.objects 封装了增删改查
sut = models.Student.objects.create(name='王六',age=33,sex=2,birthday='2021-12-18')
print(sut.name) # 使用实例化的对象调用对应的字段显示内容
print(sut.age)  
print(sut.sex)
print(type(sut)) # <class 'app01.models.Student'> model类
# create方法中在添加完成后会返回一个实力对象,可以通过实力对象打印字段对应的数据

基础查询

QuerySet查询集,里面的元素是统一类型,模型类对象
列表内的元素可以是不同类型
QuerySet类型是django中内部的一个数据类型和列表相似,相当于列表中存放的是类的实例化对象
obj = [obj1,obj2,obj3......]  # QuerySet类型
obj = [obj1,obj2,obj3......]  # 列表类型
也可以取利用索引取值
obj[1] # 这个值中存放着一列数据,可以通过.字段名称获取对应的数据
查出来的数据是多个就是QuerySet类型,查询的数据是单个就是models类型模型类


1.all(),查询表中的全部表内容,返回值是QuerySet类型
返回值 = models.Student.objects.all()  # 查所有
对应的sql
select * from Student 
obj = [obj1,obj2,obj3......] 支持索引,通过.字段名称获取对应的数据
obj[1].name  # 获取name字段的值
# 可以循环获取对应字段的值 for i in obj:  i.name i.age....
# 不能obj.name,必须取出来obj列表中的对象才能取name字段对应的值
    
    
2.first()和last()/按照记录的升序查询/返回的对象是一个models对象/模型类对象
x1 = models.Student.objects.first() # 取第一个值
x2 = models.Student.objects.last()	# 取最后一个值
对应的sql
select * form 表 order by 表.id asc limit 1: # 取第一个值
select * form 表 order by 表.id desc limit 1: # 取最后一个值
# 可以直接.name,.age 取值
x1.name
    
    
3.filter() 方法 返回的是一个QuerySet类型
为什么是QuerySet类型,因为按照条件查询,可能是多个也可能是1个,所以是一个querset类型    
xx = models.Student.objects.filter(name='王五',age=28) # 逻辑与类型 **and** 满足双条件

对应sql
select * from 表名 whele name='王五' and age=28;

    
4.exclude() 方法 按照条件进行排除/返回的是一个QuerySet类型
xx = models.Student.objects.exclude(name='张三')
对应sql
select * from 表名 whele not name='张三' # 获取张三以外的全部内容
    
    
5.get() 也属于过滤方法,查询的结果必须有且只有一条符合条件的记录/返回模型类models对象
# 查出来一个不会报错,查出来多个报错或者一条都不匹配也会报错
xx = models.Student.objects.get(name='王五')
对应的sql
select * from 表 whele name='王五' # 对id主键进行查询时,用的比较多或者字段唯一
    
    
6. oeder_by()一个排序方法 是QuerySet类型的内置方法/默认为升序,-为降序/返回QuerySet类型
xx = models.Student.objects.all().order_by("-age") # 按照age降序排序
对应的sql
select * from 表名 oeder by age desc 
# 如果是一个字段时,当两个值相同时,按照id进行排序
models.Student.objects.all().order_by("-age",'name') # age相同数据,按照name排序
    
    
7.count() 计数方法 返回整形类型/是QuerySet类型的内置方法
models.Student.objects.all().count()
对应sql
select  count(*)  from 表  
    
    
8.exists() 是QuerySet类型的内置方法 判断是否存在记录,返回布尔值False/True
models.Student.objects.exists() # 只会查询第一条记录,存在值返回True
或者
models.Student.objects.filter(name='张三').exists() # 根据条件找,返回False/True
对应的sql
select (a) as 'a' from 表 where name='张三' limit 1
    
    
9.values()和values_list() # sql中select字段
# values() 用的比较多
xx = models.Student.objects.all().values('name','age') # 返回值时QuerySet类型中套字典
<QuerySet [{'name': '张三', 'age': 22}, {'name': '张四', 'age': 22}]>
取值:xx[1].get('name') # 使用get方法取值
对应的sql
select 表.name,表.age from 表
可以强转为json类型: json.dumps(list(xx))
    
# values_list()
xx = models.Student.objects.all().values_list('name','age') # QuerySet类型中套元组
<QuerySet [('张三', 22), ('张四', 22), ('王五', 33), ('王六', 33)]>
    
    
10.distinct()  去重方法是QuerySet类型的内置方法 需要配合者values进行使用
models.Student.objects.values('age').distinct() # 返回QuerySet类型
<QuerySet [{'age': 22}, {'age': 33}]> # 将重复的数据去除
对应的sql
select distinct age from 表
  
    
11.set添加
直接添加到第多对多关系的第三章表中
数据 = [11,33,454,]
model对象.字段(多对多关联的表).set(数据列表)
    
values  select name age .... # 就是显示指定的字段

filter   # 就是whele过滤功能


12.reverse反向排序
models.数据库类名.objects.all().reverse()
# 将取出来的全部数据进行反向排序
# 返回一个queryset对象

模糊查询

1.包含__contains
models.Student.objects.filter(name__contains='王')
# 只要name字段中包含王字就获取
对应sql
select * from 表明 like  '%王%'

2.开头__startswith
models.Student.objects.filter(name__startswith='王')
# 只要name字段中开头是王字获取
对应sql
select * from 表明 like  '王%'

3.结尾__endswith
models.Student.objects.filter(name__endswith='王')
# 只要name字段中结尾是王字获取
对应sql
select * from 表明 like  '%王'

4.__isnull查询某字段是否是空
查询空字段__isnull
models.Student.objects.filter(name__isnull=True) # 查询name字段为空的值
models.Student.objects.filter(name__isnull=False) # 查询name字段不为空的值

5.大于小于__lt __gt __gte __lte
gt 大于
lt 小于
gte 大于等于
lte 小于等于
models.Student.objects.filter(age__lt=20) # age字段小于20的
models.Student.objects.filter(age__gt=20) # age字段大于20的
models.Student.objects.filter(age__gte=20) # age字段大于等于20值
models.Student.objects.filter(age__lte=20) # age字段小于等于20值

6.获取区间的__range
models.Student.objects.filter(age__range=(20,30)) # 获取age在 20-30之间的值

7.获取相等的值__in
models.Student.objects.filter(age__in=[22,33]) # 获取 age=22 和 age=33的值

8.日期范围查找
models.Student.objects.filter(birthday__year='1998',birthday__month='5')
# 查找 1998年 5月的值

高级查询

1.F查询 成员变量 对比 成员变量 使用的是F查询
from django.db.models import F,Q
例如:查询语文成绩大于数学成绩的
models.Student.objects.filter(语文字段__gt=F('数学字段'))
# F 查询就是将字段和字段之间进行对比或者查询的的方式 模糊查询与F查询搭配使用


2.Q查询 逻辑判断
# or 查询 | 或
models.Student.objects.filter(Q(语文字段__gt=30)|Q(数学字段__gt=50)) # 这是一个或or查询
语文大于30 或者 数学大于50的值

# and 查询 & 与
models.Student.objects.filter(Q(语文字段__gt=30)&Q(数学字段__gt=50))
语文大于30与数学字段大于50的值

# ~ 且的意思 not
models.Student.objects.filter(Q(语文字段__gt=30)~Q(数学字段__gt=50))
语文大于30 且数学小于50的值


3.聚合函数
# 和sql中的聚合一样
from django.db.models import Avg,Count,Max,Min,Sum
Avg 平均
Count 数量
Max 最大
Min 最小
Sum 求和
models.Student.objects.aggregate(Avg('age')) # 求age年龄的平均值
models.Student.objects.aggregate(Count('id')) # 表中总共有多少数据
models.Student.objects.aggregate(Max('age')) # 求age年龄最大值
models.Student.objects.aggregate(Min('age')) # 求age年龄最小值
models.Student.objects.aggregate(Sum('age')) # 求字段的和


4.分组函数 annotate()相当与group by ****
values 对应的就是group by字段
models.Student.objects.values('sex').annotate(avg_chi = Avg('age'))
# 按照 values 的sex字段进行分组,获取age的平均值
对应的sql语句
select sex,avg('age') from 表 group by sex ;
avg_chi = Avg('age') :相当与  aug('age') as avg_chi 
<QuerySet [{'sex': 1, 'avg_chi': 22.0}, {'sex': 2, 'avg_chi': 33.0}]>

values:相当与 
select  字段   from 表
annotate(avg_chi = Avg('age')) 相当于
group by 字段
'''
group by中按照那个字段进行分组时,必须要查询展示那个字段。数据表就会按照字段进行分组展示
比如 age 1  age 10 age 15
就会分为 3个,将相同的1/10/15的值分到一起,还可以配合聚合函数进行对其他字段的查询

例如
select age from group by age ; # 就是按照 age进行分组
age
1
10
15

select age,count('bx') from group by age ; 按照age进行分组后,在计算age这个年龄段的和是多少。
age	bx
1	2
10	1
15	3
'''
 
5.原生sql(不重要)
xx = models.Student.objects.raw('select * from db_student')
# 返回的对象 <RawQuerySet: select * from db_student>

xx = models.Student.objects.raw('select * from db_student')
    for i in xx:
        print(i) # 循环获取的时每一个模型类对象
# 只能循环提取

修改

1.update方法
queryset对象内的方法 ,只能时queryset对象才能使用
models.Student.objects.filter(name="张四").update(age=10)
# 如果有多个叫张四的人,那么age都会变成10


也可以使用update和F方法进行组合使用
models.Student.objects.filter(name="张四").first().update(age=F(age)-10)
# 对张四的age字段-10

2.基于模型类进行修改models对象进行修改
xx = models.Student.objects.filter(name="张四").first()
xx.name = '123'
xx.save() # 对所有的字段全部重新写入一遍,效率太低。

删除

pk 永远指向当前主键(假设主键为nid,id sid)

1.基于models对象
models.Student.objects.filter(name="张四").first().delete()
# 因为first() 返回的时一个models对象/获取第一个值

2.基于queryset对象删除
models.Student.objects.filter(name="张四").delete()
# 表中可以有多个叫张四的人,所有是一个queryset对象/筛选几个删除几个

ORM语法-表关联设置

'''
表关系分为:
1对1  :1对1时,需要在关联字段进行约束限制,1个对1个 必须有唯一约束unique属性1个人只能有1个身份证号一样
多对多 : 创建第三张表,字段可以不需要唯一约束,我叫wkx 别人也可以叫wkx 
1对多 :将关联关系在多的表中,字段可以不需要唯一约束 我叫wkx 别人也可以叫wkx 
'''

在开发中大多数都是关联关系
1个班级对应多个学生:1对多
1个出版社可以有多个书,1本书可以有多个出版社:多对多

一对多时,在多的表中创建关联关系。
多对多时,是通过创建第三张表来完成的。
1对1时,在主要使用这个表中进行关联,在表中必须存在关联字段
例如:
	1.创建一个用户表,基本信息
	2.在创建一个用户详情表,关联用户表,一对一关系
    

# 手动创建第三张表(多对多关系) 原理
关于多对多关系的创建 相当于创建了第三张表
第三张表
字段  id  xx   zz 
xx字段与第2张表的主键id生成一个1对多关系
zz字段与第2张表的主键id生成一个1对多关系
可以手动创建第三张表,进行关联其余两张表 对应1对多关系

关联创建于参数设置

# 创建表和表关系时的约束关系
db_constraint 唯一约束
db_constraint = True  方便查询 约束字段 # 默认
db_constraint = fales  不约束字段 同时也可以查询
这个就是保留跨表查询的便利(双下划线跨表查询),但是不用约束字段了
当使用这个参数时,保留表与表之间的关联关系,将唯一约束删除。防止在特定的列中有相同的两个纪录值
如果使用两个表之间存在关联,首先db_constraint=False 把关联切断,但保留连表查询的功能,其次要设置null=True, blank=True,注意on_delete=models.SET_NULL 一定要置空,这样删了不会影响其他关联的表
例如:我有一台电脑,别人也可以有一台电脑。

# 创建表关系时使用的链表:当主表删除一段数据,关联表与这段数据关联的数据也同时删除
on_delete=models.CASCADE

# related_name参数的使用:主要用于反向查询使用表名小写时,在1对多and多对多时,设置使用,可以不在使用表名小写,直接使用标识就可以
related_name = '标识内容'
反向查询: 从表.标识内容.all()

1对1表关系&多对多表关系都需要设置参数on_delete=models.CASCADE
多对多不需要设置 例如:
用户表
商品表
第三张关系表
用户1注销了账户,对应的关联商品是不删除的,其他用户已经关联了这个商品。
第三张表的记录会删除


1对1创建 # 表关系放在那都可以,那张作为主表优先考虑
models.OneToOneField(to='关联的1对1表名称', on_delete=models.CASCADE)
# 1.在表中创建一个字段 默认 字段_id
# 2.因为是1对1所以需要对这个字段创建唯一约束
# 3.进行关联表关系的创建

1对多创建 # 表关系需要在多的表中创建
models.ForeignKey(to='1这张表名称', on_delete=models.CASCADE, db_constraint=False)
# 1.在表中创建一个字段 默认 字段_id
# 2.没有使用db_constraint参数,就会默认为这个字段生成唯一约束
# 3.进行关联表关系的创建

多对多关创建  # 表关系放在那都可以,那张作为主表优先考虑
models.ManyToManyField(to='另一张需要创建多对多关系表明', db_table='不用默认生成的,手动创建')
# 1. 生成第三张表,id  默认生成:第1张表名_id  第2张表名_id
# 2. 第1张表名_id  第2张表名_id 创建唯一约束  没有使用db_constraint参数
# 3. 第1张表名_id(多) --> 1对多关联 <-- (1)关联第1张表主键id / 第2张表名_id(多) --> 1对多关联 <-- (1)关联第2张表主键id

1对1关系设置

需要设置两个表
一对一表关系:一个人只能拥有一个性别或者一个身份证
from django.db import models # 导入模块
# 作者表 副表

class AuthorDetail(models.Model): #副表
    nid = models.AutoField(primary_key=True)  
		# id字段自动添加
  	birthday = models.DateField()
    telephone = models.BigIntegerField()
	addr = models.CharField(max_length=64)

# 作者信息表  主表
class Author(models.Model): #主表

  	nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
   	age = models.IntegerField()
    #设置关联属性
	authordetail = models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)

#关联字段 
# 创建1对1关系:on_delete=models.CASCADE :当主表关系删除,从表跟着删除
# 
models.OneToOneField(参数1,参数2,参数3)
参数1:to=关联的表名
参数2:to_field=关联表的主键id
参数3:on_delete=models.CASCADE # 必须加的参数
    
# 当设置进行表的初始化时:就会在作者信息表创建一个 主表关联字段变量_id 的形成的一个字段负责和作者表进行关联
#一对一情况,在那张表中设置关联字段都可以,因为时一对一

1对1查询操作

# 基于models 对象的一对一查询
正向查询:按照字段
反向查询:按照表名小写

-----------------按照对象查询-------------------
#正向查询
# first() 使用者方法 获取的是queryset对象 中的第一个models对象

models对象 = 主表名.object.filter(字段=条件).first()
models对象.主表关联副表的字段名.副表的字段

# 可以获取对应的需要查询的信息


#反向查询
models对象 = 副表名.object.filter(字段=条件).first()
models对象.主表名(小写).主表内的字段
#可以根据副表筛选的条件 找到关联主表字段信息

# 因为主表关联副表,在获得models对象时,不仅仅存在一个表的字段信息,同时还有关联表的字段信息,利用点.字段取出值

-----------------按照双下划线查询-------------------
# 正向查询:按字段
主表名.objects.filter(字段=条件).values('主表关联副表字段__副表中的字段')

# 双下划线利用了vauers方法:根据字段获取全部的内容,前面有一个筛选条件,将内容精准
# 返回的是一个queryset对象


#反向查询:按照表名小写

副表名.objects.filter(主表(小写)__主表中的字段=条件).values('副表字段')

# 根据筛选主表的条件,调用副表的字段内容
# 返回的是一个queryset对象


# 基于双下划线的方式查询:根据主表的筛选条件找到副表的内容/根据副表筛选主表条件找到副表的内容。

1对多设置

表设置
from django.db import models # 导入模块
一对多的关系:出版社有可以出版多本书,那么出版社就是副表,因为需要出版多个书。

# 出版社表
class Publish(models.Model): # 副表
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

#书籍表   
class Book(models.Model): # 主表

    nid = models.AutoField(primary_key=True)
    title =  models.CharField(max_length=32)
    birthday = models.DateField()
    price = models.DecimalField(max_digits=5,decimal_places=2)
    
    # 设置关联字段
	publish = models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE,null=True)
    
    
#参数设置
models.ForeignKey(参数1,参数2,参数3,参数4)
参数1:关联副表的表名
参数2:关联副表的主键id
参数3:on_delete=models.CASCADE # 必须设置的值
参数4:单表字段可以为空

#当初始化表结构,会在主表生成一个字段,名字:关联字段_id 组成    

一对多查

# 基于models 对象的一对多查询
正向查询:按照字段
反向查询:按照表名小写
# 告诉 django 需要join那张表

-----------------按照对象查询------------------- 
#正向
models对象 = 主表名.object.filter(主表字段='条件).first()
models对象.关联字段名.副表字段


# 反向查询
models对象 = 副表.object.filter(副表字段='条件).first()

models对象中存放着主表中的内容             
models对象.主表名(小写)_set.all()
# 获取从副表筛选出来的条件下,主表对应的多个数据
                            
                            
-----------------按照双下划线-----------------
# filter 属于过滤字段  相当于 mysql中的 where
# values  显示字段  mysql中的select  需要显示内容  from......

# 正向:用两张表连起来的字段取查询 valuer("链接字段__和book表中需要查询的字段")
                            
主表名.object.filter(字段=‘条件’).values('主副关联字段__副表字段')
# 根据主表筛选条件,找到关联表副表中的值
                            
                            
                            
#反向:查询filter(表名__字段='查询的内容').values('呈现得内容') 
副表.object.filter(主表__字段='条件').values('副表字段')
                            
# 通过 join链接主表,按照主表的条件,查询到副表的内容                    

多对多表设置

表设置
from django.db import models # 导入模块
多对多:一本书可以有多个作者,一个作者可以有多本书

class Book(models.Model): # 主表

    nid = models.AutoField(primary_key=True)
    title =  models.CharField(max_length=32)
    birthday = models.DateField()
    price = models.DecimalField(max_digits=5,decimal_places=2)
    
    #设置关联字段
    authors = models.ManyToManyField(to='Author')
    

class Author(models.Model): # 副表

    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField() 
    
# 当设置多对多的关系时可以使用 models.ManyToManyField(参数1)
参数1:to=关联的副表名

# 在对表进行表结构时,会在数据库中创建一张 表(Django创建的)表的字段有三个:
主键id:由关联字段变量_id 组成 
主表id:由主表名_id 组成
副表id:由副表_id 组成

多对多查

# 基于models 对象的一对多查询
正向查询:按照字段
反向查询:按照表名小写
# 告诉 django 需要join那张表

-----------------按照双下划线查询------------------- 
# 正向查询

主表名.objects.filter(字段='条件').values('主副表关联字段名('Django创建的第三张表')__字段')

# 可以直接查询出来 对应条件 副表中的内容
在内部,向将主表中的条件进行筛选,Django内部创建的第三张表join副表,通过条件找到副表的字段内容,呈现、
#返回一个的结果,是一个或者多个,因为多对多关系


# 反向查询
副表名.objects.filter(主表名__字段 = '条件').values('副表字段')

# 通过join主表并且筛选当中的条件,获取副表中的字段 内容
# 多对多关系,在内部创建的第三张表是由Django关系并且帮你找到主副表连接的关系


-----------------按照对象查询-------------------
# 正向

models对象 = 主表.objects.filter(字段="条件").first()

models.关联副表的字段名.all() # 查询主表筛选后的全部内容
# 返回一个queryset对象


# 反向
models对象 =副表.objects.filter(字段="条件").first()
models对象.主表_set.all() # 根据副表的筛选条件找到主表的全部信息
# 返回一个queryset对象

总结双下划线和对象查询(关联表查询)

从主表查(关联字段) 正向
filter(参数):正向  参数是以主表的字段为筛选的字段=“筛选的要求”
values(参数):正向   参数是以 链接其副表的字段变量__副表字段中的需要查询内容

从副表查询 反向
filter(参数):反向参数是以主表名小写__筛选的字段=“删选的要求” 需要告诉django需要join那张表
values(参数):查询的内容是副表的字段

跨多张表查询

# 多张表都相互需要存在关联关系
# 基于下划线查询
# 正向查询
案例:找到手机号 111 开头 的作者出版过 全部书籍和出版名称
Book.objects.filter(authors__authordetail__telephone__startswith='111').values('title','publish__name')   
                    
1.以Book为主表进行查询                    
2.filter(authors__authordetail__telephone__startswith='111')
# book表与authors关联 通过authors表找到authordetail表
# 筛选条件:authors >>>django常见的第三张表>> authordetail表中对应的字段:telephone开头为111的
通过这样告诉django join哪些表查询(跨了4张表关系)

3.values('title','publish__name')
全部书籍:'title' # book表内的字段
出版名称:'publish__name'# 关联副表中字段



# 反向查询
案例:找到手机号 111 开头 的作者出版过 全部书籍和出版名称

Author.objects.filter(authordetail__telephone__startswith='111').values('book__title','book__publish__name')

# 基于Author 表找到关联表 authordetail中的字段telephone开头为111 正向查询
values('book__title','book__publish__name')
# book与Author是主副表关系,使用反向查询 获取书籍book__title
# Author与publish无关系,book表与publish有关联,间接获取对应的出版社'book__publish__name'

ORM语法-表关联设置案例

表结构

# 案例代码
from django.db import models

# 表关系设置
class Clas(models.Model):
    name = models.CharField(max_length=32, verbose_name='班级名称')

    class Meta:
        db_table = 'db2_clas'


class Course(models.Model):
    title = models.CharField(max_length=32, verbose_name='课程名称')

    class Meta:
        db_table = 'db2_course'


class Student(models.Model):
    sex_choices = (

        (1, '女'),
        (2, '男'),
        (3, '保密'),
    )

    name = models.CharField(max_length=32, verbose_name='姓名', unique=True)
    age = models.IntegerField(verbose_name='年龄', default=18)
    sex = models.IntegerField(choices=sex_choices, verbose_name='性别')
    birthday = models.DateField(verbose_name='生日')

    class Meta:
        db_table = 'db2_student'

    # 创建1对多关系/创建的时候会在表中创建一个关联字段 默认名称为’字段_id‘
    # db_constraint=True 不想要约束的话,将参数db_constraint=False/外键约束
    # related_name ='xxx' 用于相关联的clas进行反向查询时的标识,clasmodels的对象.xxx.all()
    clas = models.ForeignKey(to='Clas',related_name ='xxx' , on_delete=models.CASCADE, db_constraint=False)

    # 多对多关系的创建
    # 可以手创建第三张表进行多对多关系
    # 创建第三张表 会将当前的表和关联的表进行拼接生成第三张表Course_Student
    # 也可以手动创建 第三张表的名称db_table=手动创建第三张表名称
    # 多对多关联属性在那张表都可以
    course = models.ManyToManyField(to='Course', db_table='db2_student2course')

    # 创建1对1关系/添加这个参数on_delete=models.CASCADE 按照级联删除/在数据库中生成一个关联字段  stu_detail_id
    stu_detail = models.OneToOneField(to='StudentDetail', on_delete=models.CASCADE)


class StudentDetail(models.Model):
    tel = models.CharField(max_length=11, verbose_name='手机号')
    addr = models.CharField(max_length=32, verbose_name='住址')

    class Meta:
        db_table = 'db2_studentdetail'

1对多 and 1对1 的关联记录'添加'

from django.shortcuts import render, HttpResponse
from app01 import models # 添加模型类

# Create your views here.

def add_student(request):
    # 添加记录 针对1对多添加
    # 在创建 1对多和1对1时,就会在表后创建关联,直接对django创建的字段进行赋值就可以
    # clas_id 一对多,值是可以重复的
    # stu_detail_id 一对一,是有唯一约束的,所以不能重复。
    # 只要表中存在的字段,都是可以打印的。
    stu = models.Student.objects.create(name='hh',age=33,sex=1,birthday='2021-12-10',clas_id=1,stu_detail_id=4)
    
    clas_id 是与班级进行关联的 1对多django创建的字段
    stu_detail_id 是用户的详情表相关的 django创建的字段 1对1
    '''
    查询李四的班级名称(用select语句查询)
    select clas_id from Student whele name = '李四' 获取的事班级号为1
    select name  ffrom clas whele id = '1' # 查询到李四的班级名称
    # stu.clas 是一个模型类对象 models对象
    print(stu.clas.name)
    stu:添加用户返回的变量,这个变量是一个models对象
    因为关联的原因,1对多/1对1,django将对象进行简化
    models.Clas.objects.filter(pk=4).first()(models对象)  ==  stu.clas(django帮助我们进行了简化)
    # django提前做了操作
    
    可以直接用户对象调 1对多and1对1的表进行获取对应表中的内容
    
    '''
    return HttpResponse('添加关联记录成功')



# 重中之重 **********************
可以直接用户对象调 1对多and1对1的表进行获取对应表中的内容
例如:
lisi = models.用户表.objects.get(name='李四') # 使用get方法返回的就是一个model对象
# 在利用这个对象进行调 相关联的 其他表(只能是1对1和多对多)
lisi.班级表.name  # 调班级的名称
lisi.详情表.addr  # 调详情表中的李四的电话 

# 重中之重 **********************
只要关联的表为 1对1 and 1对多,就可以利用models的对象 调关联表的名字.字段获取对应的值

多对多的关联记录的增删改查

因为多对多第三张关联表是有manytomanyfield创建的,所以无法进行model.表名进行create添加
    
 1.添加   
    # 方式1
    1.查询用户的models对象使用get方法
    2.查询与用户表对应关系的model对象使用get方法
    3.多对多关系字段在那张表中,就用 
        manytomanyfield那张表models对象.manytomanyfield多对多关系字段.add(关联的从表models对象)
        相当于:
        主表内有manytomanyfield字段
        从表中没有
        主表models对象.多对多关联字段.add(从表models对象)
    4.就会将主表的models对象的主键id 与 从表models对象的主键id 存放在第三张表中


    例如案例代码:

        # 1.多对多 添加 查询对应的用户get方法 返回models对象
        # 2.利用这个models对象,获取多对多字段的名称进行添加  models对象.多对多字段.add

        # 1.查询对应的用户的 的models对象
        sut = models.Student.objects.get(name='张三')
        sut1 = models.Student.objects.get(name='王五')
        sut2 = models.Student.objects.get(name='李四')
        sut3 = models.Student.objects.get(name='hh')
        # 2.查询对应选修课对应的models对象
        c1 = models.Course.objects.get(title='近代史')
        c2 = models.Course.objects.get(title='思修')
        c3 = models.Course.objects.get(title='篮球')
        c4 = models.Course.objects.get(title='逻辑学')
        c5 = models.Course.objects.get(title='轮滑')
        # 3.因为Student内有多对关系的字段所以使用Student表的models对象
        sut.course.add(c1,c2)
        sut1.course.add(c3,c2)
        sut2.course.add(c3,c4)
        sut3.course.add(c4,c5)


    方式2:直接插入对应的id
    sut = models.Student.objects.get(name='张三')
    sut.course.add(7,8) # 插入从表的主键id

    方式3:使用*[]进行传参 # 用的比较多
    sut = models.Student.objects.get(name='张三')
    sut.course.add(*[1,2,3]) # 插入从表的主键id 使用*args进行传参 位置传参
    
    
2.删除
	1.找到对应用户的models对象 主表
    2.利用models对象.第三张关系表的字段名称
    3.进行remove
  	4.和添加的上面3中方式都可以使用
    
    # 删除多对多关系
    # 和添加的上面3中方式都可以使用
    sut = models.Student.objects.get(name='张三') # 找到对应的用户的models对象
    sut.course.remove(1)  # models对象.第三张关系表的字段名称.remove(从表主键id)
    
	# clear方法 删除全部和models对象的所有(只删除第三张表中的内容) 清除方法
    # 将第三张表与张三关联的内容全部删除
    sut = models.Student.objects.get(name='张三') # 找到对应的用户的models对象
    sut.course.clear()  # models对象.第三张关系表的字段名称.clear() 
    
 3.修改
    # set方法 重置方法/之前的记录全部删除,重新添加
   	sut = models.Student.objects.get(name='张三') # 找到对应的用户的models对象
    sut.course.set([8,7])  # models对象.第三张关系表的字段名称.set(列表) 

4.查看
	通过一个all()方法将全部的关于张三的内容在第三张表中查询到
    # 返回的对象是一个QuerySet类型,可以通过索引取元素,也可以通过.字段 获取用户表关联从表的内容
	sut = models.Student.objects.get(name='张三') # 找到对应的用户的models对象
	sut1.course.all() # models对象.第三张关系表的字段名称.all() 


# 都要依赖与多对多关系的那个字段,就是一个入口进行增删改查操作    

关联查询

1.基于对象查询,按照models对象为下次查询的条件

一般关联字段都会在主表中创建,获取主表models对象,利用models对象.关联字段的变量可以直接获取到models对象关联从表的数据,在通过.从表字段名获取详细数据。
# 必须是主表.关联字段变量
正向查询:主表关联从表,按照关联字段(关联字段放在哪个表,哪个表就是主表)
反向查询:从表关联主表,按照表名小写

# 1.1对多对象查询/1的那个部分是models对象,多的部分是QuerySet类型
学生查班级就是models对象  正向 
班级查学生就是QuerySet类型 反向
基于对象的查询 (子查询) 以一个查询的结果为下一个查询的子条件
    正向查询:查询王五所在的班级 按照关联字段
        ret = models.Student.objects.get(name='王五') # 返回的是models对象
        print(ret.clas.name)  # 返回的是models对象

    反向查询:查询网络1班的全部学生 # 按照表名小写_set 因为是1对多关系,一个班级多个学生
        ret = models.Clas.objects.get(name='网络1班')
        print(ret.student_set.all()) # 返回的是一个QuerySet类型

        # 方式2 在1对多或者多对多字段中设置参数related_name = '标识内容'
        假设:设置参数 related_name = 'xxx'
        ret = models.Clas.objects.get(name='网络1班')
        print(ret.xxx.all()) # 可以使用表示进行获取班级对应的全部内容 返回的是一个QuerySet类型

# 1对1对象查询/返回的都是models对象
	1的那个部分是models对象
	正向查询:按照关联字段
    查询李四的手机号
   	ret = models.Student.objects.get(name='李四')# 返回的是models对象
    print(ret.stu_detail.tel) # 按照主表中的关联字段进行.查询
    
    反向查询:按照表名
    查询手机号112的人的名字
  	ret = models.StudentDetail.objects.get(tel=112)# 返回的是models对象
    print(ret.student.name) #按照从表.主表的小写表名.字段

    
# 多对对 对象查询/返回全部是QuerySet类型
	多的一方查询返回的都是QuerySet类型
	正向查询:按照字段
    ret = models.Student.objects.get(name='王五')# 返回的是models对象
    print(ret.course.all()) # 返回QuerySet类型
    
    反向查询:按表名小写
    ret = models.Course.objects.get(title='逻辑学')# 返回的是models对象
    print(ret.student_set.all()) # 返回的QuerySet类型
    # 方式2 在1对多或者多对多字段中设置参数related_name = '标识内容'

2.基于双下划线查询(join查询)

# 重点 
    1.正向按照字段
    2.反向按照表明小写
    3.选择不同的表跨表的方式不同,必须按照关联

在原生的join表时,重要是按照关联字段进行拼接
1.1对多拼接 1对1拼接
select * from 主表 inner join 从表 on 主表.关联字段 = 从表.主键id;
主表中的关联从表的的字段  =  从表.主键id
join的本质:将关联表进行拼接在一起。

2.多对多拼接,在django中第三张表是由系统创建的/join了两次
# 表1 join 表3 join 表2 (通过表1join表3这层关系在join表2) 
select * from 
第一张表 
inner join
第三张表 
on 
第一张表.主键id = 第三张表.关联id
inner join
第二张表
on
第二张表.主键id = 第三张表.关联id;

############基于双下滑线查询############
filter() : 相当于 sql原生的语句中 whele
values() :相当于 sql原始语句中的 select 查询内容


# 查询年龄大于22的学生名称和所在班级
select 学生表.name,班级表.name from 学生表 inner join 班级表 on 学生表关联班级表字段 = 班级表.id whele age > 22;
# 正确的sql:
select  
db2_student.name,db2_clas.name 
from 
db2_student 
inner join 
db2_clas 
on 
clas_id = db2_clas.id
where age>20;

1.values # {1对多/ 多对多都是一样使用的}
# 使用orm进行查询年龄大于22的学生名称和所在班级
正向查询:按照字段,关联字段在哪个表,那么这个表就是主表正向
# 重点 :filter是sql原生中的whele  values时sel原生的 select 显示的字段
res = models.Student.objects.filter(age__gt=22).values('name','clas__name')

# 班级为网络1班年龄大于22岁的学生名称
反向查询:按照表名小写
# 重点 :filter是sql原生中的whele  values时sel原生的 select 显示的字段
ret = models.Clas.objects.filter(name='网络1班').values('name','student__name')

2.filter # {1对多/ 多对多都是一样使用的}
正向查询:按照字段,关联字段在哪个表,那么这个表就是主表正向
# 查询手机号为110的用户名称和班级 条件跨表
models.Student.objects.filter(stu_detail__tel=100).values('name','clas__name')

反向查询:按照表名小写
# 查询手机号为110的用户名称和班级 条件跨表
models.Clas.objects.filter(student__stu_detail__tel=110).values('name','student__name')
用户表为主表找到详情表中的字段为tel=110 为条件  班级表跨用户表反向 用户表跨详情表正向
显示班级表中 name字段,与主表用户表中的name字段 



# 注意:
# 显示: select 显示字段 from ......
正向查询:按主表关联从表字段 # 显示字段在 从表中
values :如果显示的字段在从表中,就需要# 主表关联字段__从表中的字段
反向查询:按照表名小写	# 显示字段在 主表中
values :如果显示的字段在主表中,就需要# 主表名小写__主表中的字段
 
# 条件 : select .....from .... whele 条件 
正向查询:按照主表关联从表的字段 # 查询条件在 从表中
filter:如果条件字段在从表中,就需要 # 主表关联字段__从表中的字段 条件
反向查询:按照表名小写 # 查询条件在 主表中
filter:如果条件字段在主表中,就需要# 主表名小写__主表中的字段 条件
    

正向查询: 按照主表查从表
反向查询: 按照从表查询主表



######### 连续夸表查询(跨多张表查询) ########
# 按照条件在当前表中情况  values参数进行跨表
查询手机号为110的学生名称和所在班级 跨了3张表
sql语句
select db2_studentdetail.tel,db2_student.name,db2_clas.name from
db2_studentdetail
inner join
db2_student
on db2_studentdetail.id= db2_student.stu_detail_id
inner join
db2_clas
on db2_student.clas_id=db2_clas.id
where tel =110;
orm写法:
ret = models.StudentDetail.objects.filter(tel=110).values('tel','student__name','student__clas__name')
# 按照当前表条件,查电话,和他的名字
获取名字 : 
	student__name :从表查主表 反向查询:按照表名小写 
获取班级:
	student__clas__name:从表查主表 反向查询:按表明小写,student查clas为主查从,正向查询按字段
# 信息表与学生表 1对1关系  学生表与班级表 1对多关系 借助中间表进行查询


# 条件在别的表中的情况 filter 参数进行跨表
查询手机号为110的学生名称和所在班级 使用db2_student主表 连三张表
sql原生语句:
select
db2_student.name,db2_clas.name
from db2_student 
inner join db2_studentdetail 
on db2_student.stu_detail_id = db2_studentdetail.id
inner join db2_clas 
on db2_student.clas_id=db2_clas.id
where db2_studentdetail.tel=110;

orm写法
ret = models.Student.objects.filter(stu_detail__tel=110).values('name','clas__name')
# 正向跨条件stu_detail__tel ,显示正向跨clas__name

基于双下划线分组查询

关于 left join 与 inner join 的区别
left join :没有匹配的字段也会显示
inner join :只显示匹配到的字段

在使用annotate分组查询时,values必须在前面,不在时 select 显示字段 而那时group by
values : 相当与 sql中的 group by属性 按照什么字段进行统计 # 重点
annotate: 相当于 sql中的 select 显示的字段 计数字段


# 案例: 查询每一个班级的学生数量
from django.db.models import Avg,Count,Min,Max # 聚合函数
反向查询:按表名小写
values('name') :使用当前表中的name 作为统计值 
annotate(c= Count('student__name') :反向查询 用表名找到主表的name 计数字段
models.Clas.objects.values('name').annotate(c= Count('student__name')) # 为别名

# 查询每一个班级的学生数量
正向查询:按照字段
values('clas__name') : 正向查询,找到班级的名称 作为统计值
annotate(c=Count('name')) :使用当前表中name值为统计值,计数字段
models.Student.objects.values('clas__name').annotate(c=Count('name'))



# 如果使用的all进行分组
models.Clas.objects.all().annotate(c = Count('student__name')) # 按照每一个字段进行分组
返回的是一个QuerySet类型的对象 [obj1,obj2.obj3] # 这个obj1对象中多了一个c统计的属性
         
         
# 案例查询每一个学生的姓名和选修课程个数并从高到低进行排序
models.Student.objects.all().annotate(c=Count('course__id')).order_by('c').values('name','c')        
# 在分组中最常用的就是all分组
1.当进行all分组时,会将全部字段进行分组,将分组的这个字段存在QuerySet类型的对象中
2.在使用values 进行显示字段
3.统计的字段annotate(c=Count('course__id')) 按照这个部分进行 找到与之关联的字段,进行计数,完成后在存储在QuerySet类型
         
当使用 all().annotate进行分组时原生sql语句
select * from 表 group by 字段 ;

ORM语法高级

queryset对象

# queryset的特性属于django中独特的类型


1.可以使用切片/索引  因为queryset列表存储对象 [obj,obj,obj]
models.表.objects.all()[0:5] # 不支持负索引

2.可以迭代
n = models.表.objects.all()
for i in n:
	print(i)
    
3.惰性查询/查询集 创建查询集不会对数据库进行访问,只有使用了查询集django才会执行这个查询
迭代器就是一个惰性查询
n = models.表.objects.all() # 使用到n才会执行从数据中获取数据
# 只有使用n这个值,才会执行sql方法,不用不会执行

4.缓存机制:只有遍历的queryset才会缓存
n = models.表.objects.all() # 缓存为空 不执行sql
print(n) # 访问数据库,就会执行对一个的sql *1
print(n) # 不会缓存,照样执行对应sql *1

只有便利了queryset对象才会缓存
ret = [i for i in n ] # 在遍历以后,就会缓存数据
print(n) # 不执行sql,从缓存中拿
print(n) # 不执行sql,从缓存中拿
print(n) # 不执行sql,从缓存中拿
#如果使用的事缓存数据,就不会从数据库中获取数据,如果引用了n*3,那么orm语句就会对应的执行3遍效率低 
# 如果进行了遍历就会将数据存储在缓存中,就只会执行便利的那一次引用的sql执行,在对orm语句进行操作时,就会从缓存中获取数据。效率提高
方式2:使用if语句,也可以将orm数据存储到缓存中



5.exists()与iterator()方法2
# exists()优化查询方案
# 查询某张表存在记录 每一个数据类型都有一个0值 空 在布尔值中:bool("")为False,其他的都为Teur
n = models.表.objects.all() # 将全部的记录取出来,如果有10w条数据,效率就会特别慢,进行判断时
可以使用exists方法
if n.exists(): # 翻译为sql就是 limit 1 ,从表中取一个值,存在Teur/不存在Falase
    ....
else:
    ....

# iterator()方法
当queryset对象数据量很大时,cache会成为问题
当处理成千上万条数据时,如果进行缓存,那么内存就会很浪费,会出现进程锁死,程序崩溃
为了避免在大量的缓存数据就是用iterator()方法,处理完毕的缓存数据丢弃
n = models.表.objects.all().iterator() # 将queryset数据不一次性的压到内存中,而是生产一个迭代器对象(将缓存压缩为一个迭代器)
ret = [i for i in n ] # 在遍历以后,就会缓存数据
将查出来的数据,不压入内存,而是放入迭代器中,用一个拿一个,不生产缓存在数据库,而那时生产迭代器

量大:iterator()
量小:使用[i for i in n ] # 就会产生缓存数据

中介模型(不创建第三关联表时)

中介模型 : 在多对多表关系下,不想用django自动创建的第三张表,自定义创建一个第三张关系表

如何创建第三张关系表
使用through关键字属性:告诉django按照哪个表进行创建第三张表
models.ManyTOManyField(to='关联的多对多关系',through='表名')
class 表名:
	字段1 = models.ForeignKey(表1) # 必须生成
	字段2 = models.ForeignKey(表2) # 必须生成
	... 其他字段
	... 其他字段
# 比django创建的第三张表,字段要多,根据用法使用
添加数据或者删除操作/就按照普通的模型进行操作
直接掉表就可以
models.表名.objects.添加()
models.表名.objects.修改()

# 可以直接操作第三张表,如果使用ManyToManyField创建,只能借助django进行控制

反向生成模型

将数据库的表,映射为models.py文件的类中 逆向过程

python manage.py inspectdb > 创建的文件名称 models文件名

查询优化

# 1.select_related('放多个表明必须是1对1/1对多')方法

select_related()方法:主要针对1对1和1对多字段,进行queryset进行优化 /将表进行josn在一起,但是queryset对象才能使用
# 查询书名为乱世佳人的出版社/执行了两个sql语句
book = models.书本表.objecs.get(title='乱世佳人') # models对象
book.出版社表名.name # 获取到对应出版社

# 优化版,执行一个sql语句
book =models.书本表.objecs.filter(title='乱世佳人').select_related('出版社表名').first() # 返回的还是models对象
models.书本表.objecs.filter(title='乱世佳人').select_related('出版社表名') # queryset对象
# 作用:将两张表join到一起,成为一张表,那么相当于执行来了一条sql语句
book.出版社表.name # 获取对应的出版社/当两张表合在一起后,怎么拿数据就会从合表中拿


# 2.prefetch_related() 作用和select_related一样都是为了减少对数据库的查询sql的数量 多对多表关系
book_list =models.书本表.objecs.all()
for  i in book:
    print(i.作者表.name) # 这个操作就是,先获取书本的全部内容执行一次sql语句,获取一个queryset对象列表
    # 循环时,每一个queryset对象列表中的对象都会进行sql语句的查询,有1w条就会查询1w次,效率太低
    
    
# 优化/数据量越大,速度越快
book_list =models.书本表.objecs.prefetch_related('作者表').all() # 这一步就是将书本表和作者表进行join在起,就是合表
book_list中的queryset对象列表中的对象,都是合过表的对象
for i in book_list:
    pritn(i.作者表.name) # 就会执行2次sql语句1.查询数据全部内容的 2.将书籍表与作者表join在一起的。

extra语句

语法:
queryset对象 = models.表名.extra(select={'属性':"表中的字段 ><= '查询的条件'"})
# 执行以后queryset对象中每一个对象都会多一个属性值,属性值会根据 对应的条件显示0和1,0代表不满足条件 1代表满足条件

queryset对象 = models.表名.extra(whele=["表中的字段 ><= '查询的条件'"])
# 执行后,会将满足条件的数据留下,不满足的数据剔除


# 可以执行sql中得大于小操作

标签:__,name,models,DjangoORM,查询,语法,objects,主表
From: https://www.cnblogs.com/kaixinblog/p/17878607.html

相关文章

  • [转]vue3+tsx开发语法详解
    原文地址:vue3+tsx开发语法详解-知乎很多组件库都使用了TSX的方式开发,主要因为其灵活性比较高,TSX和SFC开发的优缺点就不介绍了,这里主要说一下将SFC项目改造为TSX的过程。安装JSX库pnpminstall@vitejs/plugin-vue-jsx-D安装完之后在vite.config.ts进行插件使用,代码如下......
  • java基础语法-pageage-构造方法-继承-多态
    java中的包-package包:包中有很多的类,根据类的功能不同,我们可以创建不同的包。包的主要功能:包的主要功能:用于分类管理包的基本语法package包的路径路径与路径之间使用点隔开:package.fatherlujing.sonlujing在一个文件中,可以没有包,或者一个包。但是不能出现两个包。......
  • 手写类似于BetterScroll样式的左右联动菜单 uni-app+vue3+ts (使用了script setup语法
     注意:在模拟器用鼠标滚动是不会切换光标的,因为使用的是触摸滑动。【自定义类型贴在最后了】script部分如下:import{onMounted}from'vue'importtype{orderDetail}from'@/types/category'importtype{mainArr}from'@/types/main-arr'import{nextTick,ref}......
  • Markdown语法入门与进阶指南
    一、Markdown简介Markdown是一种轻量级标记语言,创始人为约翰·格鲁伯(johnGruber)。它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。Markdown在线编辑器--一个覆盖广泛主题工具的高......
  • 【算法】远方来信,从数学表达式算法到汇编语法解释器
    在繁华的都市中,小悦作为一名软件工程师,每天都在这座钢筋水泥的森林里忙碌。她的生活似乎被工作和各种琐碎的事情填满了,但在这个繁忙的生活中,她总能在工作之余找到一些小小的乐趣。这天下班后,小悦收到了一封来自国外同学苏菲的email。邮件的内容让她的思绪一下子飘回了那个学习汇......
  • Python基础_01_MarkDown语法基础
    MarkDown基础语法[一]Typora(1)下载官网:Typora官方中文站(typoraio.cn)正版价格及介绍:89元/3台设备;89元三个设备码(重装系统设备码失效)绿色版:网盘链接[.\Typora\resources文件夹下替换(app.asar)](2)部分设置主题更改:Typora官方主题库下载完成后,解压压缩包后将.css......
  • Java 基础语法:语法、变量与运算
    第一章:Java入门第二章:基础语法、变量一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴......
  • 递归下降语法分析程序
    一、目的通过设计、编制、调试一个递归下降语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,掌握常用的语法分析方法。通过本实验,应达到以下目标:(1)掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。(2)掌握语法分析的实现方法......
  • C++入门:掌握基本语法和面向对象编程
    C++入门:掌握基本语法和面向对象编程C++是一种通用的、高级的编程语言,广泛应用于开发各种应用程序。对于初学者来说,掌握C++的基本语法和面向对象编程是一个重要的起点。本篇博客将介绍C++的基本语法和面向对象编程的基本概念。了解C++的基本语法注释在C++中,你可以使用两种方式添加注......
  • php语法速记
    PHP是一种免费、通用、开源、跨平台的服务器端脚本语言,广泛应用于处理动态网页、与数据库交互、开发web应用程序等领域。PHP文件表现形式:PHP文件在服务器端运行,默认文件扩展名是".php",文件中可包含静态文本、JavaScript代码和php代码,并输出静态页面到浏览器。  一、php基......