Django(七、模型层)

模型层

模型层前期准备

使用django ORM要注意

1.django自带的sqlite3数据可对时间字段不敏感,有时候会展示错乱,所以我们习惯切换成常见的数据库比如MySQL。

2.django ORM并不会自动帮我们创建数据库,所以我们需要提前准备好‘db001’库

3.id字段是自动添加的,如果想自定义主键,只需要在其中一个字段中店家primary_key=True,如果django发现你已经明确的设置了Field.primary_key,它将不会自动添加ID列

4.django支持mysql5.5及更高版本。

默认不允许单独测试某个py文件,如果想要测试某个py文件,一般是测试models.py文件

测试环境1:pycharm提供的python console(临时保存,不推荐使用)

测试环境2:自己搭建(自带的test或者自己创建的py文件)

1.拷贝manage.py前四行代码
2.自己再添加两行
	import django
    django.setup()

代码演示:

tests.py

# manage.py中拷贝前四行代码
import os
import sys
if __name__=='__main__':  # 需要在__name__下运行
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject6.settings')# 1.引入django配置文件
    # 手写两行
    import django
    django.setup()  # 2.启动django
	# 导入app01文件夹内models文件并 测试models文件内User运行
    from app01 import models
    models.User.objects.all()

models.py

class Userinfo(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    age = models.IntegerField(null=True)
    register_time = models.DateTimeField(verbose_name='注册事件', auto_now_add=True)

    """
    DateField       : 年月日
    DateTimeField   : 年月日 时分秒
    
    两个重要参数
    auto_now        : 每次操作数据的时候 该字段会自动将当前时间更新 
    auto_now_add    : 在创建数据的时候会自动将当前创建时间记录下来 之后只要不人为的修改 那么就一直不变
    """

	def __str__(self):
        return self.username

在这里插入图片描述

切换MySQL数据库

1.提前终端创建好库db001
2.将DATABASES的配置更改
	DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db001',
        'USER':'root',
        'PASSWORD':'123123',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'CHARSET':'utf8'

    }
}
3.连接MySQL库,数据迁移
4.makemigrations
5.migrate
如何查看django ORM 底层原理?

django ORM本质还是SQL语句。

1.如果有QuerySet对象,那么可以直接点query查看SQL语句

res2 = models.Userinfo.objects.values_list('id', 'username')
print(res.query)
SELECT `app01_userinfo`.`id`, `app01_userinfo`.`username` FROM `app01_userinfo`

结论:有些不是QuerySet对象,就不能通过点query的形式点出来,就只能使用通过的方法

2.如果想查看所有ORM底层的SQL语句,也可以直接在配置文件添加日志记录

res1 = models.User.objects.create(name='kimi',age=16)
print(res.query)  # 会报错

settings最后>>>拷贝代码放在settings

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常见关键字
基础的增删改查
方法返回值
create(字段名=数据)刚创建的数据记录对象
filter(筛选条件)QuerySet列表对象
filter().update(修改内容)受影响的行数
filter().delete()受影响的行数即各表受影响的行数
常用的关键字
create描述
filter创建数据并直接获取当前创建的数据对象
first/last根据条件筛选数据 结果是QuerySet [数据对象1,数据对象2]
update拿queryset里面第一个元素/拿queryset里面最后一个元素
delete删除数据(批量删除)
all查询所有数据 结果是QuerySet [数据对象1,数据对象2]
values根据指定字段获取数据 结果是QuerySet [{}},{},{},{}]
values_list根据指定字段获取数据 结果是QuerySet [(),(),(),()]
distinct去重 数据一定要一模一样才可以 如果有主键肯定不行
order_by根据指定条件排序 默认是升序 字段前面加负号就是降序
get根据条件筛选数据并直接获取到数据对象 一旦条件不存在会直接报错 不建议使用
exclude取反操作
reverse颠倒顺序(被操作的对象必须是已经排过序的才可以)
count统计结果集中数据的个数
exists判断结果集中是否含有数据 如果有则返回True 没有则返回False

常见的十几种查询

if __name__=='__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day06_1.settings')  # 1.引入django配置文件
    import django
    django.setup()  # 2.启动django
    from app01 import models
    res = models.Userinfo.objects.filter(pk=1).first()  # 查询id为1的数据
    print(res)

    # 查询所有数据,但是只要id和username字段
    res1 = models.Userinfo.objects.values('id', 'username')
    for i in res1:
        print(i['id'],i['username'])

    res2 = models.Userinfo.objects.values_list('id', 'username')  # 取出来的对象是列表套元组,可以通过索引取值
    print(res2)  # <QuerySet [(1, 'jack'), (2, 'jerry'), (3, 'tank')]>
    print(res2[0][1])  # jack
    print(res2.query)  #  SELECT `app01_userinfo`.`id`, `app01_userinfo`.`username` FROM `app01_userinfo`查看底层的SQL语句

    res3 = models.Userinfo.objects.all().values('password').distinct()  # distinct 去重
    print(res3)  # <QuerySet [{'password': '123'}, {'password': '222'}]>

    res4 = models.Userinfo.objects.all().order_by('id')  # order_by 默认按照升序排序,在需要查找的值中加一个-号就是降序,可以添加多个字段排序
    print(res4)

    res5 = models.Userinfo.objects.all().order_by('-id').reverse()  # reverse 反转排序,前提是已经排过序了
    print(res5)

    res6 = models.Userinfo.objects.filter(password=123).count()  # count 统计当前数据的个数
    print(res6)

    res7 = models.Userinfo.objects.exclude(pk=1)  # exclude 查询除了id=1的所有数据
    print(res7)

    res8 = models.Userinfo.objects.filter(pk=4).exists()  # exists 查询当前数据是否存在
    print(res8)

    res9 = models.Userinfo.objects.create(username='sb',password=123)  # 添加数据
    print(res9)

基于双下滑线的查询

    1 年龄大于35岁的数据
    res = models.User.objects.filter(age__gt=35)
    print(res)
    2 年龄小于35岁的数据
    res = models.User.objects.filter(age__lt=35)
    print(res)
    大于等于 小于等于
    res = models.User.objects.filter(age__gte=32)
    print(res)
    res = models.User.objects.filter(age__lte=32)
    print(res)

    年龄是18 或者 32 或者40
    res = models.User.objects.filter(age__in=[18,32,40])
    print(res)

    年龄在1840岁之间的  首尾都要
    res = models.User.objects.filter(age__range=[18,40])
    print(res)

    查询出名字里面含有s的数据  模糊查询
    res = models.User.objects.filter(name__contains='s')
    print(res)

    是否区分大小写  查询出名字里面含有p的数据  区分大小写
    res = models.User.objects.filter(name__contains='p')
    print(res)
    忽略大小写
    res = models.User.objects.filter(name__icontains='p')
    print(res)

    res = models.User.objects.filter(name__startswith='j')
    res1 = models.User.objects.filter(name__endswith='j')

    print(res,res1)


    查询出注册时间是 2020 1月
    res = models.User.objects.filter(register_time__month='1')
    res = models.User.objects.filter(register_time__year='2020')

多表操作

ORM外键字段的创建
跟MySQL外键关系一样判断规律

1.一对多  外键字段建在多的一方
2.多对多  外键字段统一建在第三张关系表
3.一对一  建在任何一方都可以,但是建议建在查询频率较高的表中
注意:目前关系的判断可以采用表与表之间换位思考原则

基础表的准备

1.创建基础表(书籍表、出版社表、作者表、作者详情)
2.确定外键关系

    一对一  ORM与MySQL一致 外键字段建在查询较高的一方 
    一对多  ORM与MySQL一致 外键建在多的一方
     多对多  ORM比MySQL有更多的变化
     
	 1.外键字段可以直接建在某张表中(查询频率较高的)
           内部会自动帮你创建第三张关系表
         2.自己创建第三张关系表并创建外键字段
            后续讲解

3.ORM创建
针对一对多和一对一同步到表中之后自动加_id的后缀,如book中的外键字段publish,会自动变成publish_id。

1.一对多关系
publish= models.ForeignKey(to='Publish',on_delete=models.CASCADE)
在多的表中建立外键字段,会在表中产生一个实际的字段(自动加_id后缀)
2.一对一
author_detail = models.OneToField(to='AuthorDetail',on_delete=models.CASCADE)
在查询频率较高的表中建立外键字段,会在表中产生一个实际的字段(自动加入_id后缀)

针对多对多,不会在表中有展示,而是自动创建第三张表

1.多对多
authors=models.ManyToManyField(to='Author')
在查询频率较高的表中建立外键字段(ORM自动创建的,也可自己创建),不会在表中产生实际的字段,而是告诉ORM创建第三张关系表。

模型创建一对一、一对多和多对多的实例
在这里插入图片描述

需要注意

1.创建一对多的关系:

和SQL语句一样,外键建立到多的那一张表上,不同的是,我们可以不讲究连表和被关联的建立顺序。字段类为ForeignKey
在django2.x版本以上,建立一对多关系时需要指定on_delete参数为CASCADE,不加会报错,不过也不一定就是CASCADE,可能为其他实参。
建立外键是,系统会自动加上_id后缀作为字段名。

2.创建多对多关系

SQL中是将两张表建立好后,将外键字段创建在第三张表中,而Django为我们省去了这一步,我们可以在多对多关系双方的一个模型表中直接建立一个虚拟外键,ManyToManyField
在底层,sql依旧创建了第三张表来存储两表的多对多关系,但是在orm操作中我们就可以将模型表中的外键当做实实在在的联系,因为在查询时,我们看不到第三张表的存在
多对多关系的外键没有on_delete关键字参数。

3.创建一对一关系

一对一字段类为OneToOneField,建议建立在查询频率高的一方。
建立一对一关系时需要指定on_delete参数,否则报错。

创建表

models.py

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)

    # 一对多
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 级联删除级联更新
    # 多对多
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)

    # varchar(254)  该字段类型不是给models看的 而是给后面我们会学到的校验性组件看的

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # 一对一
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()  # 电话号码用BigIntegerField或者直接用CharField
    addr = models.CharField(max_length=64)

一对多外键增删改查

1.  直接写实际字段 id
models.Book.objects.create(title='论语',price=899.23,publish_id=1)
models.Book.objects.create(title='聊斋',price=444.23,publish_id=2)
models.Book.objects.create(title='老子',price=333.66,publish_id=1)
2.  虚拟字段  使用对象创建
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=666.23,publish=publish_obj) # 通过对象增加一本书
models.Publish.objects.filter(pk=1).delete()  # 级联删除,删除id=1的所有数据

修改
models.Book.objects.filter(pk=1).update(publish_id=2)
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)

多对多的外键增删改查

多对多外键属于实际不在模型表中的虚拟字段,多对多关系则需要django提供给我们的方法来实现增删改关系。拿到设立多对多外键的模型表的对象,用它点出外键属性,可以进行add、set、remove方法,这些方法都是这条记录对象的操作。

给书籍添加作者id
语法:book_obj.authors.add()   
       # 对象.外键.add()
  add可以通过关联的id或者关联的对象进行绑定关系

    book_obj = models.BooK.objects.filter(pk=1).first()
    1.书与作者一对一绑定
    book_obj.authors.add(1)  # 在第三张关系表中给当前书籍绑定作者
    2.书与作者一对多绑定
    book_obj.authors.add(2,3)
    3.作者对象与书对象的绑定
    book_obj = models.BooK.objects.filter(pk=4).first()
    author_obj1 =models.Author.objects.filter(pk=2).first()
    author_obj2 =models.Author.objects.filter(pk=3).first()
    # book_obj.authors.add(author_obj1)  # 可以添加一个作者对象
     book_obj.authors.add(author_obj1,author_obj2)  # 也可同时添加两个作者对象

    总结:add(1)  add(1,2)  add(obj1)  add(obj1,obj2)
修改书籍作者id
语法:book_obj.authors.set()  
       # 对象.外键.set()
  set可以通过关联的id或者关联的对象进行修改绑定关系


 4.绑定错误,如何修改使用set修改关系
   	""" 通过id修改的"""
    book_obj = models.BooK.objects.filter(pk=4).first()
    book_obj.authors.set((1,3))  # set括号里面只能填写一个可跌倒对象()/[]或者对象
    """ 原本id=4的书籍绑定的是作者2和作者3,通过set修改数据信息后绑定的是作者1和作者3"""
    
    book_obj.authors.set([2,4])
    """通过对象修改的"""
    
    book_obj = models.BooK.objects.filter(pk=2).first()
    book_obj.authors.add(1,2,4)
    """ id=2的书绑定了作者1,作者2和作者4"""
    
    book_obj = models.BooK.objects.filter(pk=2).first()
    author_obj1=models.Author.objects.filter(pk=1).first()
    author_obj2=models.Author.objects.filter(pk=2).first()
    author_obj4=models.Author.objects.filter(pk=4).first()
    book_obj.authors.set((author_obj1,author_obj2))
    """ id=2的书由绑定的作者1,作者2和作者4修改为作者1和作者4"""
    
    book_obj.authors.set((author_obj1,author_obj2,author_obj4))
    """ 通过修改,id=2的书还是绑定了作者1,作者2和作者4"""
	
	总结set((1,))  set((1,2))  set((obj1,))  set((obj1,obj2))
删除
  语法:book_obj.authors.remove()   
       # 对象.外键.remove()
  remove可以通过关联的id或者关联的对象进行移除绑定关系
  
5.数据的删除
    book_obj= models.BooK.objects.filter(pk=1).first()
    author_obj1= models.Author.objects.filter(pk=1).first()
    author_obj2= models.Author.objects.filter(pk=2).first()
    """ 通过id去删除"""
    book_obj.authors.remove(2)  # 作者2
    #book_obj.authors.remove(1,3)
    """ 通过作者对象去删除"""
    book_obj.authors.remove(author_obj1)  # 作者1
    #book_obj.authors.remove(author_obj1,author_obj2)

	总结:remove(1)  remove(1,2)  remove(obj1)  remove(obj1,obj2)
  
  add()\remove()	多个位置参数(数字 对象)
  set()			  可迭代对象(元组 列表) 数字 对象 
  clear()	      情况当前数据对象的关系 ,不需要传参数
数据清空(clear)
      语法:book_obj.authors.clear()   
          # 对象.外键.clear()
      clear() 直接清空与book的id1关联的所有作者
	  
	  
    """ 清空主键为1的绑定关系"""
    book_obj = models.BooK.objects.filter(pk=1).first()
    book_obj.authors.clear()

ORM跨表查询

MySQL跨表查询的思路

1.子查询
分步操作:将一条SQL语句用括号括起来当做另外一条SQL语句条件

2.连表操作
先整合多张表之后基于单表查询即可
inner join
left join
right join

ORM跨表查询的思路

正反向查询的概念
1.正向查询
右外键字段所在的表数据查询关联的表数据

2.反向查询
没有外键字段的表数据查询关联的表数据

总结:正反向的核心就看外键字段在不在当前数据所在的表中

ORM跨表查询的口诀

正向查询按外键字段
反向查询按表名小写

基于对象的跨表查询(子查询)
在这里插入图片描述
步骤:
1.先根据条件获取数据对象
2.判断正反向查询(正向查询按外键,反向查询按表名小写)

正向查询

1.查询主键为1的书籍对应的出版社名称

先根据对象获取数据
book_obj=models.Book.objects.filter(pk=1).first()
再判断正反向的概念,由书查出版社 外键字段在书所在的表中,所以是正向查询,正向查询按外键字段
print(book_obj.publish.name)

2.查询主键为2的书籍对应作者姓名

book_obj=models.Book.objects.filter(pk=2).first()
由书查作者 外键字段在书所在的表中 所以是正向查询
print(book_obj.authors.all())
print(book_obj.authors.all().values('name'))

3.查询作者为jack的电话号码

book_obj = models.Author.objects.filter(name='jack').first()
print(book_obj.author_detail.phone)

反向查询

4.查询出版社是东瀛出版社出版的书

book_obj = models.Publish.objects.filter(name='东瀛出版社').first()
print(book_obj.book_set.all())

5.查询作者是jack写过的书

book_obj = models.Author.objects.filter(name='jack').first()
print(book_obj.book_set.all())

6.查询手机号是111的作者姓名

book_obj = models.AuthorDetail.objects.filter(phone=111).first()
print(book_obj.author)
总结
正向查询:数据对象可以点出它有的外键字段的名称属性
反向查询:数据对象可以点出关联它的表名小写_set的名称属性

连表查询(基于双下划线的跨表查询)

1.查询jack的手机号和作者姓名

res = models.Author.objects.filter(name='jack').values('name', 'author_detail__phone')
print(res)

2.查询书籍主键为1的出版社名称和书的名称

res = models.Book.objects.filter(pk=1).values('title', 'publish__name')
print(res)

3.查询书籍主键为1的作者姓名

res = models.Book.objects.filter(pk=2).values('authors__name')
print(res)

4.查询书籍主键是1的作者的手机号

res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
print(res)

聚合查询

聚合函数:Max、Min、Sum、Count、Avg

函数名描述
Max大于
Min小于
Sum求和
Count统计某个数据
Avg平均值

如果我们在ORM中使用聚合函数,ORM支持单独使用聚合函数,步骤如下:

1.引入模块
from django.db.models import Max,Min,Sum,Count,Avg
2.使用关键字aggregate
res = models.Book.objects.aggregate(Max('xx'),Min('xx'),最小价格=Sum('xx'),拼averge=Avg('xxx'))  # 建议取名要英文,不要用中文

eg:
     
    from django.db.models import Max,Min,Sum,Count,Avg
    res= models.BooK.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price'))
    print(res)  # {'price__max': Decimal('999.05'), 'price__min': Decimal('222.98'), 'price__sum': Decimal('3332.59'), 'pk__count': 5, 'price__avg': Decimal('666.518000')}

分组查询

引入

​ 如果执行ORM分组查询报错,并且又关键sql_mode / strict mode ,那么就去移除sql_mode中的only_full_group_by

1.统计每一本书的作者个数

res = models.BooK.objects.annotate(author_num=Count('authors__pk')).values('title','author_num')
print(res)

2.统计出每个出版社卖的最便宜的书的价格

    res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    print(res)

3.统计不止一个作者的图书

1.先统计每本书的作者个数
    res = models.Book.objects.annotate(author_num=Count('authors__pk'))
2.筛选出作者个数大于1的数据    
    res = models.BooK.objects.annotate(author_num =Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')
    print(res)

4.查询每个作者出的书的总价格

res=models.Author.objects.annotate(book_sum=Sum('book__price')).values('name','book_sum')
print(res)

上述分组是按照表来分组,我们也可以按照表中的字段名来分组

1.按照表分组
models.表名.objects.annotate()
2.按照表中字段名来分组
models.表名.objects.values('字段名').annotate()

eg:
	res=models.Book.objects.values().annotate(count_pk=('pk')).values('publish_id','count_id')
	print(res)
	注意:values在annotate前就是按照values()括号里面字段名来分组;values()在annotate后就是按照前面的表名分组,values就是拿值的

F与Q查询

注:字段中填写了两个参数,一个是null,即允许为空(默认情况下为非空),一个是default默认值,即在记录中这个字段如果没有填写则自动填充的值。如果不设置这两个参数,那么再添加这两个字段的时候,因为表中已经有数据了,所以原本记录的这两个字段既要求非空有没有默认值就无法迁移。然后,涉及到我们的数据迁移,需要执行那两条命令makemigrations、migrate.

数据添加,首先在Book表中添加两个字段库存数和卖出数。但是由于我们前面就已经数据迁移过了,那么如何处理呢?

"""后续添加两个字段,必须要加入默认值"""
inventory_number=models.IntegerField(verbose_name='库存数',default=1000)
number_sold = models.IntegerField(verbose_name='售出数',null=True)

在这里插入图片描述
将售出数添加后保存方便后续操作,如下展示
在这里插入图片描述

F 查询

当查询条件不是很明确的,也需要从数据库中获取,就需要使用F查询。
简单理解:

  1. 两个字段进行比较的筛选条件(库存数大于卖出数)
  2. 在原来的数值字段增在数值(888)
  3. 在原来的字段名后面加字(爆款)
    在上述条件等,我们只借助于ORM操作,是实现不了的,我们需要再ORM中借助F方法。

1.查询库存数大于卖出输的书籍

from django.db.models import F
res = models.Book.objects.filter(inventory_number__gt=F('number_sold')).values('title')
print(res)

2.将所有的书涨价800

res = models.Book.objects.update(price=F('price')+800)

在这里插入图片描述
3.将所有书的名称后面加上爆款两个字
在操作字符类型的数据的时候 F不能够直接做到字符串的拼接
需要借用Concat和Value模块

from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'), Value('爆款')))

Q 查询

在ORM操作中,筛选条件中存在或、非的关系需要借助Q方法来实现。

符号描述
,and的关系
~not的关系

1.查询主键是1或者价格大于两千的书籍

1.常用的查询方法
    res = models.BooK.objects.filter(pk=1,price__gt=2000).values('title')  # 逗号默认是and关系
    print(res)

2.逗号是and
    from django.db.models import Q
    res = models.BooK.objects.filter(Q(pk=1),Q(price__gt=2000)).values('title')  # 逗号是and
    print(res)

3.|or
    res1 = models.BooK.objects.filter(Q(pk=1) | Q(price__gt=2000)).values('title')  # |是or
    print(res1)

4.~not
    res2 = models.BooK.objects.filter(~Q(pk=1 ) | Q(price__gt=2000)).values('title')  # ~是not
    print(res2)

总结:
两个条件是或关系Q(条件1) | Q(条件2)
两个条件是非关系~Q(条件)

Q查询进阶操作
from django.db.models import Q
q_obj = Q()  # 1.产生一个Q对象
q_obj.connector =''   # 默认是多个条件的连接时and
q_obj.connector ='or'  # 可以修改为or
q_obj.children.append(('pk',1)) # 2.添加查询条件
q_obj.children.append(('price__gt',2000)) # 支持添加多个
res = models.Book.objects.filter(q_obj)  # 查询支持直接填写Q对象

查询条件成为’字符串’,也就意味着,可以让用户交互,进行筛选条件的选择与添加。

ORM查询优化

1.ORM的查询默认都是惰性查询
2.ORM的查询自带分页处理

将来如果自己做SQL,最好要加上LIMIT分页

3.only与defer

# res = models.Book.objects.all() # 获取所有的[数据对象1,],不走sql语句
只想拿某些字段的话,使用value,但是value拿到的是[{},{},{}]。只有only可以实现
1.only
    '''数据对象+含有指定字段对应的数据'''
    # res = models.Book.objects.only('title', 'price')
    # print(res)  # queryset [数据对象、数据对象]
    # for obj in res:
        # print(obj.title)  # 点击括号内填写的字段 不走SQL查询
        # print(obj.price)
        # print(obj.publish_time)  # 可以点击括号内没有的字段获取数据 但是会走SQL查询
        
    总结:only会将括号内填写的字段封装到数据对象中,后续获取不走SQL,但是获取括号内没有的字段数据则需要走SQL
        
2.defer   
    res = models.Book.objects.defer('title', 'price')
    # print(res)  # queryset [数据对象、数据对象]
    for obj in res:
        # print(obj.title)  # 点击括号内填写的字段 走SQL查询
        # print(obj.price)
        print(obj.publish_time)  # 点击括号内没有的字段获取数据 不走SQL查询
        
 总结:defer会将括号内填写的字段封装到数据对象中,后续获取有字段需要走SQL,但是获取括号内没有的字段数据则不需要走SQL

4.select_related与prefetch_related
括号内都是只支持一对一和一对多外键字段,多对多外键字段是不支持的。

1.select_related  连表操作
    # res = models.Book.objects.all()
    # for obj in res:
    #     print(obj.publish.name)  # 每次查询都需要走SQL
""" 通过点book外的表,每次查询都会走SQL,如果不想走SQL,可以将两个表连起来后再查询不走SQL语句"""
    # res = models.Book.objects.select_related('authors')  # 先连表后查询封装
    # res1 = models.Author.objects.select_related('author_detail')  # 括号内不支持多对多字段 其他两个都可以
    # print(res1)
    # for obj in res:
    #     print(obj.publish.name)  # 不再走SQL查询

   """ select_related括号内填写一对多、一对一字段 自动连表然后继续数据封装"""
2.prefetch_related  子查询
    res = models.Book.objects.prefetch_related('publish')  # 子查询
    for obj in res:
        print(obj.publish.name)
        
   """ prefetch_related括号内填写一对多、一对一字段 基于子查询然后封装数据  """
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值