Django之ORM模型层
1、仿写 Django 中Settings.py的配置文件
-
Django配置文件的原理是:
Django中其实是有两个settings.py文件.一个是系统默认的,一个是暴露给用户的.这样做的好处在于:一个专业名词叫可插拔式配置文件.
-
可插拔式配置文件
当用户配置了settings,那么系统就会加载用户的配置文件,反之,就加载系统默认的配置文件,这样就算用户不配置,系统也不会报错,基于这点,我们在今后的项目可以引入这一概念.
1.1设置可插拔式配置文件的思路.
读取用户的配置文件,其他就是读取settings.py中的参数,通常都是配置参数为大写,后面为参数值如下:
NAME='我是暴露给用户的配置文件'
- 建立工程

1.2 代码实现.
----conf
|----settings.py # 暴露给用户的配置文件
----lib
|---conf
|----init.py # 自动加载
|----global_settings.py # 系统默认配置文件
start.py # 启动文件
start.py
import sys
import os
# 下面这两句话在pycharm中会自动帮我们将当前的环境路径,但是出了pycharm,其他的软件就不识别了。
BASE_DIR=os.path.dirname(__file__)
sys.path.append(BASE_DIR)
# 设置环境变量默认为用户自定义的配置文件。
os.environ.setdefault('xxx','conf.settings')
from lib.conf import settings
print(settings.NAME)
conf.settings.py
NAME="我是用户自定义的Django系统配置文件"
lib.conf.global_settings.py
NAME="我是默认的Django默认的系统配置文件"
lib.conf.__init.py
class Settings(object):
def __init__(self):
for setting in dir(global_settings):
if setting.isupper():
k=setting
# 从global_settings(对象)中获取k对用的值
v=getattr(global_settings,setting) # global_settings对象中取k的值
setattr(self,k,v) # self 是本类的对象. # 设置环境变量,k,v.
# 从全局的大字典中获取到暴露给用户的配置文件路径
mod=os.environ.get('xxx')
# mod=conf.settings
moudel=importlib.import_module(mod)
# from conf import settings
for setting in dir(moudel):
if setting.isupper():
k=setting
v=getattr(moudel,setting)
setattr(self,k,v)
# 循环获取默认的配置文件中所有的大写配置
# 利用setattr给对象不停的设置键值对
# 再循环获取暴露给用户的自定义配置文件中所有的大写的配置
# 再利用setattr给对象不停的设置键值对
settings=Settings()
2、orm基本使用
2.1 准备工作
2.1.1 新建一个py文件,用来测试
#添加manage.py的环境变量
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day60.settings")
# 导入django
import django
django.setup()
# 引入models模块
from app01 import models
2.1.2 后台打印对应的mysql语句。
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
},
}
}
2.2 单表查询基本使用
models.py
from django.db import models
# Create your models here.
class Books(models.Model):
title=models.CharField(max_length=32)
price=models.DecimalField(max_digits=8,decimal_places=2)
date=models.DateField()
def __str__(self): # 必须是str类型才会被调用
return self.title
terminal>>> python manage.py makemigration
terminal>>> pyhton manage.py migrate
2.2.1 增
# 第一种
res=models.books.objects.create(title='三国演义',price=123.34,date='2019-08-09')
# 第二种
book_obj=models.books(title='三国演义',price=123.34,date='2019-08-09')
book_obj.save()
2.2.2 删
models.books.filter(pk=1).delete()
2.2.3 改
# 第一种
models.books.filter(pk=1).update(title='厚黑学')
# 第二种
book_obj=models.books.filter(pk=1).first()
book_obj.price=567.56
book_obh.save()
2.2.4 查(单表查询,必知必会13条)
2.2.4.1 查询所有 all
# 1、 查询所有 all() QuerySet对象
res=models.Books.objects.all()
for i in res:
print(i.title)
2.2.4.2 条件查询 filter
# 2、 条件查询 filter() QuerySet对象
models.Books.objects.filter(pk=1)
2.2.4.3 条件查询 get
# 3、条件查询 get 数据本身的对象. 查不到就报错,不推荐使用
res=models.Books.objects.get(title='论语')
print(res.price)
2.2.4.4 queryset对象的第一个 first
#4、 条件查询 first() QuerySet对象
res=models.Books.objects.all()
print(res.first().title)
2.2.4.5 queryset对象的最后一个 last
# 5、 条件查询 last() QuerySet对象
res = models.Books.objects.all()
print(res.last().title)
2.2.4.6 除……之外 exclude
# 6、 除什么之外 exclude() QuerySet对象 后面可以一直加排除项目
res = models.Books.objects.all().exclude(pk=3)
# res = models.Books.objects.all().exclude(pk=3).exclude(pk=4)
for i in res:
print(i.title)
2.2.4.7 列表套字典 values QuerySet
# 7、 列表套字典 values() QuerySet对象
res = models.Books.objects.values()
print(res)
for i in res:
print(i.get('title')) # 不能用句柄了.
<QuerySet [{'id': 3, 'title': '论语', 'price': Decimal('888.88'), 'date': datetime.date(2014, 5, 6)}, {'id': 4, 'title': '三国演义', 'price': Decimal('123.32'), 'date': datetime.date(2019, 7, 19)}, {'id': 5, 'title': '红楼梦', 'price': Decimal('56.23'), 'date': datetime.date(2022, 3, 4)}]>
论语
三国演义
红楼梦
2.2.4.8 列表套元祖 values_list
# 8、 列表套元祖 values_list() QuerySet对象
res = models.Books.objects.values_list()
print(res)
<QuerySet [(3, '论语', Dewqcimal('888.88'), datetime.date(2014, 5, 6)), (4, '三国演义', Decimal('123.32'), datetime.date(2019, 7, 19)), (5, '红楼梦', Decimal('56.23'), datetime.date(2022, 3, 4))]>
2.2.4.9 统计数据个数count
## 9、 count 统计数据的个数
count_res=models.Books.objects.all().count()
count_res1=models.Books.objects.count()
print(count_res,count_res1)
# 3,3
2.2.4.10 去重 distinct
## 10、 distinct 去除重复
count_res = models.Books.objects.all().distinct()
count_res1=models.Books.objects.values('title','price').distinct()
print(count_res1)
<QuerySet [{'title': '论语', 'price': Decimal('888.88')}, {'title': '三国演义', 'price': Decimal('123.32')}, {'title': '红楼梦', 'price': Decimal('56.23')}]>
2.2.4.11 排序 order_by
## 11 order_by 排序
res=models.Books.objects.all().order_by('price') # 默认是升序
res1 = models.Books.objects.all().order_by('-price') # 加负号降序
print(res,res1)
2.2.4.12 反序 reverse
# 12.reverse() 前面必须是先结果排序才可以反转
res = models.Books.objects.order_by('price').reverse()
print(res)
2.2.4.13 查询是否存在 exists
# 13.exists() 一点卵用没有 True or False
res = models.Books.objects.filter(pk=3).exists()
print(res)
2.3 神奇的双下划线
2.3.1 条件大于、小于、大于或等于
# 1、大于 __gt
res=models.Books.objects.filter(price__gt=100)
print(res)
# 2、小于 __lt
res=models.Books.objects.filter(price__lt=100)
print(res)
# 3、大于等于 __gte
res=models.Books.objects.filter(price__gte=56.23)
print(res)
# 4、小于等于 __lte
res=models.Books.objects.filter(price__lte=123.32)
print(res)
2.3.2 条件符合其中某一个
# 5、 符合某一个条件__in=[a,b,c,d]
res=models.Books.objects.filter(price__in=[123,123.32,56.32])
print(res)
2.3.3 条件符合在a和b之间
# 6、 在区间__range=(a,b)
res=models.Books.objects.filter(price__range=(123,888.88))# 顾前面的整数,不顾小数
print(res)
2.3.4 包含某个字符
# 包含字母P __contains
res=models.Books.objects.filter(title__contains='p') # 区分大小写
print(res)
res1=models.Books.objects.filter(title__icontains='P') # 不区分大小写
print(res1)
2.3.5 开头以某个字符
# __startswith='' 字符串
res1=models.Books.objects.filter(title__startswith='三') # 开头是三
res2=models.Books.objects.filter(title__endswith='p') # 开头是三
print(res1,res2)
2.3.5 查询日期
# __year __month
res1=models.Books.objects.filter(date__year='2014') # 查询年份
res2=models.Books.objects.filter(date__month='08') # 查询月份
print(res1,res2)
2.4 多表查询
model.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=True)
# 书和出版社 1对多
publish=models.ForeignKey(to='Publish')
# 书和作者 多对多
authors=models.ManyToManyField(to='Author')
class Publish(models.Model):
name=models.CharField(max_length=32)
addr=models.CharField(max_length=64)
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
# 作者和作者细节 1对1
author_detail=models.OneToOneField(to='AuthorDetail')
class AuthorDetail(models.Model):
phone=models.BigIntegerField()
addr=models.CharField(max_length=64)
python manage.py makemigrations
python manage.py migrate
2.4.1 1对多关系(基本操作)
2.4.1.1 添加数据(外键)
# publish_id 属于 虚拟字典
# publish_id直接传出版社主键值
models.Book.objects.create(title='三国演艺',price=123.23,publish_id=1)
# publish直接传出版社数据对象(这种比较常用)
publish_obj=models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='水浒传',price=234.45,publish=publish_obj)
2.4.1.2 查询数据(外键)
##### 2.4.1.1 添加数据(外键)
# 2、查询
res=models.Book.objects.filter(pk=1).first()
print(res.publish)
print(res.publish_id)
# OUTPUT
东方出版社
1
2.4.1.3修改数据(外键)
# 3、修改
#publish_id直接传出版社主键值
# models.Book.objects.filter(pk=1).update(publish_id=3)
# publish直接传出版社数据对象(这种比较常用)
publish_obj=models.Publish.objects.filter(pk=3).first()
models.Book.objects.filter(pk=2).update(publish=publish_obj)
2.4.1.4 删除数据(外键)
models.Publish.objects.filter(pk=3).delete()
# 默认也是级联更新 级联删除
2.4.2 多对多关系(基本操作)
2.4.2.1 增加 add
# add 可以添加数字,也可以添加对象.并且支持多个
# 给主键为3的书籍添加两个作者 3,4
book_obj=models.Book.objects.filter(pk=5).first()
#book_obj.authors.add(3)
book_obj.authors.add(4,6)
# 给主键为3的书籍添加两个作者对象 3,4
book_obj = models.Book.objects.filter(pk=5).first()
author_obj=models.Author.objects.filter(pk=3).first()
author_obj1=models.Author.objects.filter(pk=4).first()
book_obj.authors.add(author_obj,author_obj1)
2.4.2.2 改 set
# 2、改 可以添加数字,也可以添加对象,支持多个,如果修改的书籍已经存在了,就不会忽略.括号内对象必须可迭代.
# 修改主键为3的书籍,修改对象为4,6
book_obj=models.Book.objects.filter(pk=5).first()
book_obj.authors.set([4,6])
# 也可以传对象来修改。
book_obj = models.Book.objects.filter(pk=5).first()
author_obj = models.Author.objects.filter(pk=3).first()
author_obj1=models.Author.objects.filter(pk=4).first()
book_obj.auhtors.set(author_obj)
book_obj.authors.set((author_obj,author_obj1))
2.4.2.3 删除 remove
# 3、 删除 可以数字,可以对象.支持多个.
#book_obj=models.Book.objects.filter(pk=5).first()
#book_obj.authors.remove(3,4)
book_obj = models.Book.objects.filter(pk=5).first()
author_obj = models.Author.objects.filter(pk=3).first()
author_obj1=models.Author.objects.filter(pk=4).first()
book_obj.authors.remove(author_obj,author_obj1)
2.4.2.4 清空 clear
# 4、清空 所有关于主键为5的书所有的作者信息。 # clear不能有任何数据.
book_obj = models.Book.objects.filter(pk=5).first()
book_obj.authors.clear()
2.5 跨表查询
2.5.1 正反向查询
正向查询、反向查询
举个例子.a表和b表有关系,并且,外键在a,从a查b的数据,就是正向查询.从b查a的数据,就是反向查询.
两个查询的方向不同,用到的方法也有所不同.
# 1.查询书籍是python入门的出版社名称
book_obj=models.Book.objects.filter(title='python入门').first()
print(book_obj.publish.name)
print(book_obj.publish.addr)
# 2.查询书籍主键是6的作者姓名
book_obj = models.Book.objects.filter(pk=6).first()
print(book_obj.authors.all().first())
#3.查询作者是jason的手机号
author_obj=models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.phone)
'''
正向查询
.对象
如果查询如果超过1个,需要加all()
'''
# 4、查询出版社是机械出版社出版过的书籍
publish_obj=models.Publish.objects.filter(name='机械出版社').first()
print(publish_obj.book_set.all())
# 5.查询作者是jason写过的所有的书
author_obj=models.Author.objects.filter(name='tank').first()
print(author_obj.book_set.all())
# 6.查询手机号是19356615618的作者
author_detail_obj=models.AuthorDetail.objects.filter(phone=19356615618).first()
print(author_detail_obj.author.name)
'''
反向查询
.小写表名_set
如果查询如果超过1个,需要加all()
什么时候需要加_set
当查询的结果可以是多个的情况下 需要加_set.all()
什么时候不需要加_set
当查询的结果有且只有一个的情况下 不需要加任何东西 直接表名小写即可
'''
# 题目中,从a查b那么,拿的对象就是a的.抓住题目.
2.5.2 双下划跨表查询
2.5.2.1 真正的正反向查询
若a和b表存在关系,那么orm对象中,拿a的对象去取b的值,则是正向.拿b的对象取b的值则是反向.
# 1.查询书籍是python入门的出版社名称
# 正向
res=models.Book.objects.filter(title='python入门').values('publish__name')
print(res)
# 反向
res1=models.Publish.objects.filter(book__title='python入门').values('name')
print(res1)
# 2.查询作者是jason的手机号码
# 正向
res=models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
print(res)
# 反向
res1=models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
print(res1)
# 3.查询手机号是19356615618的作者姓名
# 正向
res=models.AuthorDetail.objects.filter(phone='19356615618').values('author__name')
print(res)
# # 反向
res1=models.Author.objects.filter(author_detail__phone='19356615618').values('name','age')
print(res1)
# 4.查询出版社是东方出版社出版的书籍名称
res=models.Publish.objects.filter(name='东方出版社').values('book__title')
print(res)
# # 反向
res1=models.Book.objects.filter(publish__name='东方出版社').values('title')
print(res1)
#
# # 5.查询作者是jason的写过的书的名字和价格
res=models.Author.objects.filter(name='jason').values('book__title','book__price')
print(res)
# # 反向
res1=models.Book.objects.filter(authors__name='jason').values('title','price')
print(res1)
#
# # 7.查询书籍是python入门的作者的手机号 从这author表跨到author_detail中.其中__
res=models.Book.objects.filter(title='python入门').values('authors__author_detail__phone')
# 反向
res=models.AuthorDetail.objects.filter(author__book__title='python入门').values('phone')
print(res)
2.6 聚和查询(函数) aggregate
from django.db.models import Max,Min,Sum,Avg,Count
res=models.Book.objects.all().aggregate(Avg("price"),Count('title'),Sum('price'),Max('price'),Min('price'))
# res=models.Book.objects.aggregate(Avg("price"),Count('title'),Sum('price'),Max('price'),Min('price'))
print(res)
#{'price__avg': 90.22, 'title__count': 4, 'price__sum': Decimal('360.88'), 'price__max': Decimal('124.53'), 'price__min': Decimal('34.67')}
2.7 分组查询 annotate
相当于mysql的groupBy
# 1.统计每一本书的作者个数
# 按书分组,从书找作者是正向 直接写book类中的authors对象
res=models.Book.objects.annotate(author_num=Count('authors')).values('author_num')
print(res)
# 2.统计出每个出版社卖的最便宜的书的价格
# 按出版社分组,从出版社找书,反向的。book__price
res=models.Publish.objects.annotate(min_price=Min('book__price')).values('min_price')
print(res)
# 3.统计不止一个作者的图书
"""
1.统计每本书对应的作者个数
2.基于上面的结果 筛选出作者个数大于1 的
"""
res=models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('author_num')
print(res)
# 4.查询各个作者出的书的总价格
# 作者查书
res=models.Author.objects.annotate(book_sum=Sum('book__price')).values('book_sum')
print(res)
2.8 F与Q查询
当我们要查询的条件不是自己手写的。而是取一个字段的所有值,需要用到F和Q
2.8.1 F查询
查询某一个字段
form django.db.models import F,Q
# 1、查询售出大于库存的书的名称
res=models.book.objects.filter(shouchu__gt=F('kucun'))
print(res)
# 2、将所有的书的价格 全部提高100块
res=models.Book.objects.update(price=F('price')+100)
print(res)
# 3、所有书的名称后面加爆款两个字
from django.db.Functions import Concat
from django.db.models import Values
res=models.Book.objects.update(name=Concat(F('title'),Vlalues('爆款')))
2.8.2 Q查询
需要 Or、And、Not条件关系
# 书名称叫python入门,或者价格等于224.53
# or
res=models.Book.objects.filter(Q(title='python入门') | Q(price='224.53'))
# and
res=models.Book.objects.filter(Q(title='python入门'),Q(price='224.53'))
# not
res=models.Book.objects.filter(~Q(title='python入门'),~Q(price='224.53'))
print(res)
# 需求变了,需要如果title 是用户手动输入的。传到后面判断,怎么操作?
q=Q()
q.connector='or'
#q.children.append(('title','python入门'))
"""
字符串的左边 跟你的变量名条件书写一模一样
"""
q.children.append(('title__icontains','q')) # 注意是一个元组对象。也可以使用双下划线。
q.children.append(('maichu','666'))
res=models.Book.objects.filter(q)
print(res)
2.9 orm 常用字段
2.9.1、AutoField # 自增列
- 必须填入 primarykey=true
当model中如果没有自增列,则自动会创建一个列名为id的列。.如果用户写了,那么django就忽略.
2.9.2、CharField # 相当于mysql中的varchar类型
- 必须要有max_length=number 参数. 指定长度
2.9.3 自定义Char类型.
class MyCharField(models.Field): # 1、继承models.Field
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length # 2、必须指定长度
super().__init__(max_length=max_length, *args, **kwargs) # 在调用父类的构造方法
def db_type(self, connection): # 4、重写父类中的db_type方法
return 'char(%s)' % self.max_length # char(max_length)
class TestField(models.Model):
name = MyCharField(max_length=16) # 直接用
2.9.4 IntegerField
- 一个整数类型,范围在 -2147483648 to 2147483647大小内的10位整数
2.9.5 DateField
- 日期格式 YYYY-MM-DD. 相当于Pyhton中的datetime.date()实例
- auto_now_add=True 创建数据记录的时候会把当前时间添加到数据库
- auto_now 每次更新数据记录的时候都会更新改字段
2.9.6 DateTimeField
- 日期时间字段,格式 YYYY-MM-DD HH-MM[:ss.[.uuuuuu]][TZ],相当于Python中的datetime.datetime()
- auto_now_add=True 创建数据记录的时候会把当前时间添加到数据库
- auto_now 每次更新数据记录的时候都会更新改字段
2.9.7 BooleanField
- bool
- 该字段在存储数据的时候,只需要传布尔值,
- 对应u数据库中的0/1
2.9.8 TextField
-
对应mysql中的text
-
文本类型.可以存大量的文本
2.9.9 EmailField
-
mysql Varchar(254)
-
继承CharField
-
存邮件
2.9.10 FileField
-
字符串,路径保存在数据库,文件上传到指定路径
-
参数:
upload_to=" "上传文件的保存路径
storage=None 存储组件 默认django.core.files.storage.FileSystemStorage
2.9.11 DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
2.10 字段参数说明
1、null 字段参数可以为空 null=True
2、unique 如果设置为unique=True 则该字段在此表中必须是唯一的 。
3、db_index 如果db_index=True 则代表着为此字段设置索引。
4、default 为该字段设置默认值。
ForeignKey
1、to 设置要关联的表
2、to_field 设置要关联的表的字段
3、on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。
#####################
如果你使用的是django2.X版本 你在建数据库表关系的时候
你需要手动指定两个参数
(你要手动告诉django 级联更新 级联删除 是否建外键约束)
on_delete
db_constraint
2.11 查询优化(面试常问)
2.11.1 惰性查询
- 不用不查,一用才查.
res=models.Book.objects.all() # 不用不查,用了才查。
发现sql语句没有打印
print(res) # 使用print后,就展示查询语句了.
# SELECT `app01_book`.`id`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`publish_date`, `app01_book`.`maichu`, `app01_book`.`shouchu`, `app01_book`.`publish_id` FROM `app01_book` LIMIT 21; args=()
2.11.2 only
only 会将括号内的字段, 直接封装成对象, 点该字段,不需要走数据库
一旦你点了不是括号内的字段.就会频繁的走数据库查询.
# 需求1: 通过res.,拿到title
res=models.Book.objects.values("title")
for i in res:
print(i.title)
# AttributeError: 'dict' object has no attribute 'title' 这种需要get.
res=models.Book.objects.only('title')
for i in res:
print(i.title)
# (0.044) SELECT `app01_book`.`id`, `app01_book`.`title` FROM `app01_book`; args=()
数据库只查询一次,并且直接返回对象.
- 需求2 : 通过上面的案例,我们发现,数据库中只查询了title的字段.,尝试用i.price.看看数据库查几次?
res=models.Book.objects.only('title')
for i in res:
print(i.price)
'''
(1.826) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 5; args=(5,)
223.23
178.45
(0.078) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 6; args=(6,)
(0.091) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 7; args=(7,)
224.53
(0.049) SELECT `app01_book`.`id`, `app01_book`.`price` FROM `app01_book` WHERE `app01_book`.`id` = 8; args=(8,)
134.67
'''
数据库执行了4次.
2.11.3 defer
和only相反
- defer会将括号内的字段排除之外将其他字段对应的值 直接封装到返回给你的对象中 点该其他字段 不需要再走数据库
- 一旦你点了括号内的字段 就会频繁的去走数据库查询
res=models.Book.objects.defer('title')
for r in res:
print(r.price)
#(0.044) SELECT `app01_book`.`id`, `app01_book`.`price`, `app01_book`.`publish_date`, `app01_book`.`maichu`, `app01_book`.`shouchu`, `app01_book`.`publish_id` FROM `app01_book`; args=()
223.23
178.45
224.53
134.67
2.11.4 select_related

-
自动连表操作
-
两张表连起来后,所有的字段都放在对象中. 只查询一次.
-
select_related()括号中只能是外键.并且多对多字段不能放.只能放1对1和1对多
-
如果括号内外建字段所关联的表中还有外键字段.还可以继续连表.
select_related(外键字段__外键字段__外键字段...)
res=models.Book.objects.all()
for i in res:
print(i.publish)
###########
跨表查询会查询多次.
# book表中查出版社名称
res=models.Book.objects.select_related('publish')
for i in res:
print(i.publish.name)
#############
机械出版社
机械出版社
工业出版社
机械出版社
(0.046) SELECT `app01_book`.`id`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`publish_date`, `app01_book`.`maichu`, `app01_book`.`shouchu`, `app01_book`.`publish_id`, `app01_publish`.`id`, `app01_publish`.`name`, `app01_publish`.`addr` FROM `app01_book` INNER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`); args=()
res=models.Book.objects.select_related('authors')
for i in res:
print(i.authors.name)
##############
', '.join(_get_field_choices()) or '(none)',
django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'authors'. Choices are: publish
2.11.5 prefetch_related

- 看似连表操作 其实是类似于子查
- prefetch_related括号内只能放外键字段 多对多除外.
- 并且多对多字段不能放
res=models.Book.objects.prefetch_related('publish')
for i in res:
print(i.publish.name)
################ 先查Book.id,再拿Book.id去publish表中去查.最后塞到对象里面去.
(0.056) SELECT `app01_book`.`id`, `app01_book`.`title`, `app01_book`.`price`, `app01_book`.`publish_date`, `app01_book`.`maichu`, `app01_book`.`shouchu`, `app01_book`.`publish_id` FROM `app01_book`; args=()
(0.055) SELECT `app01_publish`.`id`, `app01_publish`.`name`, `app01_publish`.`addr` FROM `app01_publish` WHERE `app01_publish`.`id` IN (4, 5); args=(4, 5)
机械出版社
机械出版社
工业出版社
机械出版社
2.11.6 select_related和prefetch_related两者之间的优劣
- Select_related 内部自动连表 消耗的资源就在连表上 但是走数据库的次数较少
- Prefetch_related 内部不做连表 消耗的资源就在查询次数上 但是给用户的感觉跟连表操作一样
2.12 Django orm事务提交
django orm中的事务操作
ACID
原子性
一致性
隔离性
持久性
commit
rollback
要么同时成功要么同时失败
# django 中如何开始事务
from django.db import transaction
with transaction.atomic():
pass
# 在该代码块中所写的orm语句 同属于一个事务
# 缩进出来之后自动结束

浙公网安备 33010602011771号