Django连接MySQL数据库
1、在settings配置文件将sqlite3数据库配置改成mysql数据裤配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'Django_db',
'USER':'root',
'PASSWORD':'root',
'HOST':'127.0.0.1',
'PORT':3306,
'CHARSET':'utf8'
}
}
2、在项目名下或者任意应用下的__init__.py文件中声明用pymysql模块,不用默认的mysqldb模块,代码如下:
import pymysql
pymysql.install_as_MySQLdb()
Django的ORM模型
ORM: 是指对象关系的映射,主要是通过python对象代码简单快捷操作数据库,该模型的不足之处:封装程度太高,有时候效率偏低,需要自己写sql语句
ORM模型常用的字段:
AutoField
int自增列,必填参数primary_key=True。即如果model没有自增列,它会自动创建一个列名为id的列
IntegerField
整数类型,范围在-2147483648 to 2147483647
DecimalField
浮点数,参数max_digits=8表示八位,decimal_places=2表示小数点占两位
CharField
字符串类型,必须提供max_length参数,用来表示字符长度
注意:该字段对应的是MySQL数据库中varchar类型,如果要使用mysql数据库中字符串的其他类型,则需要自己定义
from django.db import models
# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
'''
自定义的char类型的字段类
'''
def __init__(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)
def db_type(self, connection):
'''
限定生成的数据库表字段类型char,长度为max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
gender_choice=((1,'男'),(2,'女'),(3,'保密'))
gender=models.SmallIntegerField(choices=gender_choice,default=3)
自定义及使用
DataField
日期字段,日期格式2019-10-11,跟pythondatetime.date()实例一样
DateTimeField
日期字段,格式:YYYY-MM-DD HH:MM 跟python中datetime.datetime()实例
'''
DateTimeFiled有两个参数:
auto_now:每次操作数据的时候,该字段会自动将当前时间更新
auto_now_add:在创建数据的时候会自动将当前创建时间记录下列,之后只要不认为的修改,就不会改变
'''
EmailField,是varchar(254)
BooleanField(Field) 布尔值类型
该字段传布尔值(False/True) 数据库里存0/1
TextFiled(Field) 文本类型,没有字数限制
FileField(field) 字符类型
upload to="/data" 该字段存的是文件路径
AutoField(Field)
- int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models
class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值
CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField(Field)
- 文本类型
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field)
- 二进制类型
字段合集
常用字段的参数
null:用于表示某个字段为空
unique:设置为unique=True,则表示该字段在表中是唯一的,例如:ForeignKey(unique=True) 表示创建一对一
db_index:db_index=True,代表该字段设置为索引
default:该字段设置为默认值
参数choices的使用:
class User(models.Model):
name=models.CharField(max_length=32)
sex_choices={
(1,'男'),
(2,'女'),
(3,'其他'),
}
sex=models.IntegerField(choices=sex_choices)
res=models.User.objects.all()
for i in res:
print(i.get_sex_display())
'''
总结:如果元组第一个不是数字,是字符串,则用字符串字段。
不在元组内的数字也可以存,不会报错
获取choices参数字段的对应的值:固定语法 get_字段名_display
'''
ORM模型的数据库操作步骤:
1、建表,在应用下的models文件相应的数据库操作代码,具体例子如下:
from django.db import models
# Create your models here.
class User(models.Model):
#id int primarykey auto_icrement
id=models.AutoField(primary_key=True,verbose_name='主键')
#username varchar(32)
username=models.CharField(max_length=32,verbose_name='账号')
#password int
password=models.IntegerField(verbose_name='密码')
'''
注意:CharField必须指定max_length参数,不然会直接报错
verbose_name这个参数是用来对字段的解释,可加可不加
'''
2、在命令窗口执行数据库迁移的两条命令
python manage.py makemigrations
python manage.py migrate
注意:只要每次修改了models文件中和数据库操作有关的代码就必须重新执行上面两条命令。
3、字段的增删改
(1)字段的增加:直接在建表类下添加一个字段
#字段增加的第一种方法,根据命令窗口提示,在命令行窗口输入了新增字段的默认值
age=models.IntegerField(verbose_name='年龄')
#第二种方法,直接添加一个null=True的参数,让新增字段为空
sex=models.CharField(max_length=16,verbose_name='性别',null=True)
#第三种方法,直接添加一个默认值
hobby=models.CharField(max_length=32,verbose_name='爱好',default='study')
(2)字段的修改:直接将原有的字段那一行代码注释,重新写一行
# password=models.IntegerField(verbose_name='密码')
password=models.CharField(max_length=32,verbose_name='密码')
(3)字段的删除:直接把相应字段的那一行代码注释掉就可以。
注意:以上操作,每次都需要数据库迁移的两条命令。同时,字段的注释要仔细,因为字段的删除相应的数据也会跟着删除
数据的增删改查
1、数据的查询:
def login(request):
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get("password")
#res返回的是一个列表,列表里是存放数据对象,[数据对象1,数据对象2]
#first()方法,是获取列表中的第一个对象
res = models.User.objects.filter(username=username).first()
if res: #res有对象,则表明该用户存在
if password==res.password:
return HttpResponse('登陆成功'.encode())
else:
return HttpResponse('密码错误'.encode())
else:
return HttpResponse('用户不存在'.encode())
return render(request,'login.html')
2、数据的插入;
第一种:用User中的create方法创建一个对象
reg=models.User.objects.create(username=username,password=password)
第二种:先实例化一个User对象,并保存
reg=models.User(username=username,password=password)
reg.save()
elif aciton=="注册":
if res:
return HttpResponse('该用户名已存在'.encode())
else:
#插入数据的第一种方法
# reg=models.User.objects.create(username=username,password=password)
#第二种方法:直接先实例化一个对象,并保存
reg=models.User(username=username,password=password)
reg.save()
return HttpResponse('注册成功'.encode())
3、修改数据
def edit(request):
id=request.GET.get('edit_id')
edit_boj=models.User.objects.filter(id=id).first()
if request.method=="POST":
username = request.POST.get('username')
password=request.POST.get('password')
'''修改数据方法1
models.User.objects.filter(id=id).update(username=username,password=password)
方法1只修改,要修改的字段,其他字段不会修改。
'''
#修改数据的方法2
edit_boj.username=username
edit_boj.password=password
edit_boj.save()
'''
方法2的效率比较低,因为无论字段是否被修改,它都需要更新一遍
'''
return redirect('/showlist/')
return render(request,'edit.html',locals())
4、删除数据
def delete(request):
id=request.GET.get('dele_id')
#删除数据
models.User.objects.filter(id=id).delete()
'''
注意:现实中的删除数据并不会像上面这样把数据删除,而是通过加一个字段,来表示该数据是否删除
'''
return redirect('/showlist/')
Django的ORM建立多表关系
关系字段参数
to:设置关联的表
to_field:设置要关联的表的字段
on_delete: 参数如下:
- models.SET_NULL:置空模式,删除时,外键字段被设置为空,前提时该字段可以为空
- models.CASCADE:级联删除
- models.DO_NOTHING:删除数据的时候,不会删除到关联表的数据
- models.PROTECT:删除关联数据的时候,会报错
- models.SET_DEFAULT:删除子表数据的时候,外键字段设置为默认值
- models.SET(值): 删除关联数据的时候,自定义一个值
#一对多
publish=models.ForeignKey(to='Publish')#to_field=这个参数是设置外键关联字段,不写默认为主键
#多对多
author=models.ManyToManyField(to='Author')
#一对一
authordetail=models.OneToOneField(to='Authordetail')
'''
注意:ManyToManyField会自动帮你创建一张表
OneToOneField和ForeignKey会自动给字段加"_id"
Django 1.x版本,是默认有级联的
'''
多对多三种创建方式:
'''
第一种:全自动
优点:不用写代码,就可以自动建立第三张表,还支持orm提供操作第三张表的方法
缺点:不可以扩展,没办法添加额外字段
'''
class Book(models.Model):
name=models.CharField(max_length=32)
author = models.ManyToManyField(to='Author')
class Author(models.Model):
name=models.CharField(max_length=32)
'''
第二种:手动
优点:扩展性高,可以根据自己的需求扩展字段
缺点:需要自己写代码,不支持orm提供的操作方法,比如:add、remove等
'''
class Book(models.Model):
name=models.CharField(max_length=32)
class Author(models.Model):
name=models.CharField(max_length=32)
class Book_Author(models.Model):
book_id=models.ForeignKey(to='Book')
author_id=models.ForeignKey(to='Author')
'''
第三种:半自动
优点:可以扩展字段、可以使用orm的正反向查询
缺点:不能使用orm提供的add,set,remove,clear方法
'''
class Book(models.Model):
name=models.CharField(max_length=32)
'''
#参数解析:查作者的时候,是通过第三张表Book_Author中的book_id字段来获取author_id来查作者表
through_fields中字段的顺序,第一个是放当前表的跟第三表关联的字段,第二个是放要查询的表关联的字段。
比如:查书的作者,第一参数就是放book_id,第二个参数就是放author_id
'''
author=models.ManyToManyField(to='Author',through='Book_Author',through_fields=('book_id','author_id'))
class Author(models.Model):
name=models.CharField(max_length=32)
class Book_Author(models.Model):
book_id=models.ForeignKey(to='Book')
author_id=models.ForeignKey(to='Author')
测试环境的搭建
#测试脚本.py文件
from django.test import TestCase
'''
测试环境的搭建
'''
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "two_django.settings")
import django
django.setup()
#测试代码
'''
注意:无论是模块还是测试代码,都只能放在这里
'''
from app
十三个方法:
1、all():查询所有结果
2、fiter(**kwargs): 筛选条件符合的对象,例如:filter(name='helo',age='14')
3、get(**kwargs):返回所给筛选条件符合的对象,返回结果只有一个。返回结果超过一个,或者没有的时候,会报错,所以推荐使用filter()
4、exclude(**kwargs):筛选条件不匹配对象
5、values():凡回忆个ValueQuerySet对象,返回一个类似列表套字典的数据结构
6、values_list():跟values相似,返回的是一个列表套元组的形式
7、order_by():对查询结果排序
8、reverse():对查询结果反向排序
9、distinct():去重,注意不能出现主键字段,否则会无法去重
10、count():返回匹配的对象数量
11、first():返回第一条数据
12、last():返回最后一条数据
13、exists():判断是否存在 '''
all方法:查询所有结果
返回<QuerySet [<User: User object>, <User: User object>, <User: User object>]>
'''
r=models.User.objects.all()
'''
filter方法:获取符合筛选条件的结果
返回结果:<QuerySet [<User: User object>]>
注意:pk表示当前表的主键字段,filter括号内参数是and关系
'''
r=models.User.objects.filter(pk=3)
'''
#get方法:获取一个符合条件的对象
返回结果:User object
'''
r=models.User.objects.get(pk=2)
'''
exclude方法:排除某个条件后的结果
返回结果:<QuerySet [<User: User object>, <User: User object>]>
'''
r=models.User.objects.exclude(pk=2)
'''
#values方法:
返回结果:<QuerySet [{'name': 'jk', 'passwd': '123'}, {'name': 'hello', 'passwd': '111'}, {'name': 'json', 'passwd': '123'}]>
'''
r=models.User.objects.values('name','passwd')
'''
value_list方法:
返回结果是:<QuerySet [('jk', '123'), ('hello', '111'), ('json', '123')]>
'''
r=models.User.objects.values_list('name','passwd')
'''
orderby方法:对查询结果进行排序,默认是升序,降序只需要加个 - 就可以
返回结果:<QuerySet [<User: User object>, <User: User object>, <User: User object>]>
'''
res=models.User.objects.order_by('age')
res=models.User.objects.order_by('-age') #加-号,变降序
'''
reverse方法:反向排序,前提时已经排序好的对象才可以使用该方法
返回结果:<QuerySet [<User: User object>, <User: User object>, <User: User object>]>
'''
r=models.User.objects.order_by('age').reverse()
'''
distinct方法:去重
返回结果:<QuerySet [{'name': 'jk'}, {'name': 'hello'}, {'name': 'json'}]>
注意:不能有主键,而且必须是一模一样才可以去重
'''
r=models.User.objects.values('name').distinct()
'''
count方法:统计结果数量
返回结果是 数量值 4
'''
r=models.User.objects.all().count()
'''
first、last方法:获取第一个和最后一个
返回结果 User object'''
r=models.User.objects.all().first()
print(r.name)
r=models.User.objects.all().last()
print(r.name)
'''
exists方法:判断是否存在
返回结果是布尔值
'''
r=models.User.objects.filter(pk=2).exists()
Django终端打印SQL语句
在settings.py文件中最后添加以下配置就可以
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
双下划线查询
#获取年龄大于21的用户
r=models.User.objects.filter(age__gt=21)
# 获取年龄大于等于21的用户
r=models.User.objects.filter(age__gte=21)
#获取名字有h的结果
r=models.User.objects.filter(name__contains='h') #区分大小写
r=models.User.objects.filter(name__icontains='h') #不区分大小写
#获取年龄是18,20,23的用户
r=models.User.objects.filter(age__in=[18,20,23])
#获取age在19到21范围的用户
r=models.User.objects.filter(age__range=[19,21])
#获取注册时间是7月份的结果
r=models.User.objects.filter(regist_time__month=7)
r = models.User.objects.filter(regist_time__week_day__gte=3)
#以h开头的结果
r=models.User.objects.filter(name__startswith='h') #区分大小写
r = models.User.objects.filter(name__istartswith='h') #不区分大小写
#以0结尾的结果
r = models.User.objects.filter(name__endswith='O') #区分大小写
r=models.User.objects.filter(name__iendswith='O') #不区分大小写
外键的增删改查
#多表增删改查
#一对多
#增
'''
第一种:直接写实际字段publish_id,
第二种,用虚拟字段publish ,要放对象
'''
models.Book.objects.create(name='好好说话',price=21,publish_id=1)
p_object=models.Publish.objects.filter(pk=3).first()
models.Book.objects.create(name='无线网络传感器',price=69,publish=p_object)
#删
models.Publish.objects.filter(pk=3).delete() #级联删除
#改
models.Book.objects.filter(pk=2).update(publish_id='2')
p_object=models.Book.objects.filter(pk=4).first()
models.Book.objects.filter(pk=6).update(publish=p_object)
#多对多
#增
#add方法+id
b_object=models.Book.objects.filter(pk=7).first()
b_object.author.add(1,2)
#add方法+对象
a1=models.Author.objects.filter(pk=3).first()
a2=models.Author.objects.filter(pk=5).first()
a3=models.Author.objects.filter(pk=2).first()
b_object=models.Book.objects.filter(pk=5).first()
b_object.author.add(a2,a3)
#删除
book_object=models.Book.objects.filter(pk=3).first()
book_object.author.remove(2)
book_object.author.remove(a1,a2)
#修改
'''
set方法:括号内放的是一个可迭代对象,该对象内可以放数字也可以放对象。
'''
book_object.author.set([1,3])
book_object.author.set([a1,a2])
#清空方法
book_object.author.clear()
'''
总结:remove()、add()方法中括号内既可以传数字,也可以传对象
set() 存放可迭代对象,对象内可以放数字跟对象
'''
正向方向概念:
正向:查外键所在的表就是正向 比如:知道书的id,查书的出版社
反向:查外键不在的表就是方向 比如:知道出版社,查出版社的书
口诀:正向查询用字段,反向查询用表名小写
#查书籍id为4的出版社名字(正向)
book_obj=models.Book.objects.filter(pk=4).first()
# print(book_obj.publish.name)
#查询书籍主键为5的作者
book_obj=models.Book.objects.filter(pk=5).first()
res=book_obj.author #结果:app03.Author.None
res=book_obj.author.all() #<QuerySet [<Author: Author object>, <Author: Author object>]>
#查作者json号码
author_obj=models.Author.objects.filter(name='json').first()
res=author_obj.authordetail.iphone
#查清华出版社出版的书(反向查找)
publish_obj=models.Publish.objects.filter(name='清华出版社').first()
res=publish_obj.book_set.all()
#查作者alex写的书
author_obj=models.Author.objects.filter(name='alex').first()
res=author_obj.book_set.all()
#查询作者年龄是19的作者名称
authordetail_obj=models.AuthorDetail.objects.filter(age=19).first()
res =authordetail_obj.author
print(res.name)
'''
总结:反向查询:如果查询结果只有一个,则表名后面不需要加_set
如果查询结果有多个,则需要加_set.all
正向查询:查询结果有多个要加all(),只有一个就不用加
口诀,正向看字段,反向看表名小写。
'''
基于双下划线的跨表查询
#查json的号码
res=models.Author.objects.filter(name='json').values('authordetail__iphone')
print(res)
#反向
res=models.AuthorDetail.objects.filter(author__name='json').values('iphone')
print(res)
#查书籍id=2的名字以及出版社名字
res=models.Book.objects.filter(pk=2).values('name','publish__name')
res=models.Publish.objects.filter(book__id=2).values('book__name','name')
print(res)
#查书籍id=3的作者名字
res=models.Book.objects.filter(pk=3).values('author__name')
res=models.Author.objects.filter(book__id=3).values('name')
print(res)
#查书籍id=3的作者的电话号码
res=models.Book.objects.filter(pk=3).values('author__authordetail__iphone')
print(res)
聚合查询
#聚合查询 关键字aggregate
'''
一般跟数据库有关的都在django.db.models可以找到
找不到可以在django.db中找
'''
from django.db.models import Sum,Avg,Max,Min,Count
res=models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Avg('price'),Count('pk'))
print(res)
分组查询
#分组查询 关键字:annotate
#统计每一本书作者的个数
res=models.Book.objects.annotate(author_num=Count('author')).values('name','author_num')
print(res)
#查询作者超过1个的书籍名字
res=models.Book.objects.annotate(author_num=Count('author')).filter(author_num__gt=1).values('name')
print(res)
#查看作者写过的书的总价格
res=models.Author.objects.annotate(book_price=Sum('book__price')).values('name','book_price')
print(res)
#统计每个出版社最便宜的书的价格
res=models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
print(res)
F查询
主要用来解决两个字段之间的比较,实现动态比较
#F查询:用来解决两个字段之间的比较
from django.db.models import F
#查看库存量<卖出的书
res=models.Book.objects.filter(maichu__gt=F('kucun')).values('name')
print(res)
#将所有书籍的价格提高20元
res=models.Book.objects.update(price=F('price')+20)
'''
F进行字符的拼接需要借助两个模块
from django.db.models.functions import Concat
from django.db.models import Value
'''
from django.db.models.functions import Concat
from django.db.models import Value
#给销量大于库存的书籍名字加一个爆款
res=models.Book.objects.filter(maichu__gt=F('kucun')).update(name=Concat(F('name'),Value('爆款')))
Q查询
from django.db.models import Q
#查看价格大于100或者卖出大于一千的书籍名称
'''
filter参数是and关系,所以这里需要借助Q查询
注意:| 表示or关系 ,和& 都表示and关系
~表示取反,即not关系
'''
# res=models.Book.objects.filter(Q(price__gt=100)|Q(maichu__gt=1000)).values('name')
res = models.Book.objects.filter(Q(price__gt=100) | ~Q(maichu__gt=1000)).values('name')
print(res)
'''
Q的高阶玩法,将查询左边变成字符串,这样就可以应用到根据字段来筛选。
'''
q=Q()
q.connector='or' #默认是and关系
q.children.append(('price__gt',100))
q.children.append(('maichu__gt',1000))
models.Book.objects.filter(q)
事务
from django.db import transaction
#开启事务
try:
with transaction.atomic():
#事务代码
except Exception as e:
print(e)
print('其他操作')
数据库的优化
1、only和defer
'''
all方法:当我没有使用到all方法返回的对象res的时候,
它是不会走数据库执行的,只有用到才会走数据库
'''
res=models.Book.objects.all()
for i in res:
print(i.name)
'''
only方法:获取only括号内的字段值的时候,是不会走数据库
获取非only括号内的字段时候,才会走数据库
defer方法:跟only方法相反,获取括号内字段会走数据库,
非括号内的字段不会走数据库
'''
res=models.Book.objects.only('name')
for i in res:
# print(i.name)
print(i.price)
res=models.Book.objects.defer('name')
for i in res:
# print(i.name)
print(i.price)
2、select_relate方法、prefetch_related方法
'''
select_relate方法:
select_related会将Book表跟外键字段publish的Publish表关联起来,
然后一次性将关联后表的所有数据都封装给返回的对象res中,
这样res获取这两个表中任何一个字段的数据都不用再走数据库
注意:select_related括号内只能放一对一或者一对多的外键字段,不能放多对多的外键字段
prefetch_related方法:
本质是子查询。会将子查询出来的结果封装在res对象中,给人一种一次性查询出来的感觉。
当表比较大的时候,select_related的多表连表操作时速度会变慢,就可以用prefetch_related方法 '''
res=models.Book.objects.select_related('publish')
res=models.Book.objects.prefetch_related('publish')
for i in res:
print(i.publish.name)
总结:1、对于多对多字段和一对多字段,可以使用prefetch_related()来优化
2、对于一对一和多对一的关系,可以使用select_related来优化
3、select_related是通过减少SQL查询次数来进行优化和提高性能的
4、prefetch_related优化是通过分别查询每个表,再用python来处理他们之间的关系。
5、具体使用哪种优化最终还是得根据实际情况来选择。