Django之ORM
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:该字段设置为默认值
db_constraint=False: 表示逻辑上关联,但是实际上不受影响
#db_constraint=False,此时,如果删除出版社,对应图书不会被删除,而是出版社字段设置为null publish=models.ForeignKey(to='Publish',db_constraint=False,on_delete=models.DO_NOTHING)
参数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:设置要关联的表的字段
related_name
反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。
例如:
class Classes(models.Model): name = models.CharField(max_length=32) class Student(models.Model): name = models.CharField(max_length=32) theclass = models.ForeignKey(to="Classes")
当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:
models.Classes.objects.first().student_set.all()
当我们在ForeignKey字段中添加了参数 related_name 后,
class Student(models.Model): name = models.CharField(max_length=32) theclass = models.ForeignKey(to="Classes", related_name="students")
当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:
models.Classes.objects.first().students.all()
related_query_name
反向查询操作时,使用的连接前缀,用于替换表名。
db_constraint
是否在数据库中创建外键约束,默认为True。
symmetrical
仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。
举个例子:
class Person(models.Model): name = models.CharField(max_length=16) friends = models.ManyToManyField("self")
此时,person对象就没有person_set属性。
class Person(models.Model): name = models.CharField(max_length=16) friends = models.ManyToManyField("self", symmetrical=False)
此时,person对象现在就可以使用person_set属性进行反向查询。
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版本,是默认有级联的 '''
内置类class Meta的使用
class BaseModel(models.Model): is_delete=models.BooleanField(default=False) #创建时间 create_time=models.DateTimeField(auto_now_add=True) #更新时间 update_time=models.DateTimeField(auto_now=True) class Meta: #抽象表,一般作为基类的时候使用,不再数据库建立出来 abstract=True #用来指定model对应的数据库中的表名 db_table='书表' #排序,加个“-”号就是降序 ordering=['data']
verbose_name='xxx' #指定在admin管理界面中显示中文
verbose_name_plural='xxx' 表示复数形式的显示;中文的单数和复数一般不作区别。
多对多三种创建方式:
''' 第一种:全自动 优点:不用写代码,就可以自动建立第三张表,还支持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
ORM操作
十三个方法:
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、具体使用哪种优化最终还是得根据实际情况来选择。
Djangon ORM提供的批量插入方法:
def insert(requst):
book_obj_list=[]
for i in range(10000):
#先创建book对象,并添加到list列表中
book_obj=models.Book(name='第%s本书'%i)
book_obj_list.append(book_obj)
#将对象列表交给bulk_create处理
models.Book.objects.bulk_create(book_obj_list)
book_obj=models.Book.objects.all()
return render(requst,'insert.html',locals())