Django ORM管理
目录:
1、关系模型
2、ORM增删改查
3、QuerySet与惰性机制
4、神器的双下划线
5、单表查询、多表查询
6、关系字段
官方文档:Django 1.10 - Models and databases
一、关系模型
模型之间的三种关系:一对一,一对多,多对多。
一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性
一对多:就是主外键关系(foreign key)
多对多:(ManyToManyField) 自动创建第三张表 (当然我们也可以自己创建第三张表:两个foreign key)
二、ORM数据增删改查
增: 1、obj.create() 推荐使用create 2、obj.save() 效率不高 删: objects.filter().delete() 改: object.filter().update() 推荐使用update object.save() 效率不高 查: objects.get() 取一个对象 objects.filter() 取多个对象 objects.all() 获取所有对象
注: 如果想显示对应的row 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', }, } }
一对多表记录创建方式:
普通的值
Book.objects.create(title="python", publish_date="2017-05-05", price=100.00, publish_id=1)
对象的值
obj=Publish.objects.filter(name="北京大学出版社")[0]
Book.objects.create(title="python", publish_date="2017-05-05", price=100.00, publish=obj)
多对多关系(两张表的关系是平等的,需要抽象出第三张表来实现)
class Book:
author=models.ManyToManyField("Author") 自动创建 第三张表(不能直接对第三张表进行操作)
添加数据1方法(主语是book)
author_obj=Author.objects.filter(name="alex")
book_obj=Book.objects.fitler(id=3)[0]
book.obj.author.add(author_obj)
添加数据2方法(主语是author)
author_obj=Author.objects.filter(name="alex")[0]
book_obj=Book.objects.fitler(id__lte=3)
author_obj.book_set.add(*book_obj) //反向查询
三、QuerySet与惰性机制
Django的queryset是惰性的
所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行;因为数据库查询是显著影响web应用性能的因素之一。
要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql(为了验证这些,需要在settings里加入 LOGGING(验证方式))
obj=models.Book.objects.filter(id=3) for i in obj: print(i) if obj: print("ok")
queryset是具有cache的
当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行(evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,你不需要重复运行通用的查询。
obj=models.Book.objects.filter(id=3) for i in obj: print(i) for i in obj: print(i) #LOGGING只会打印一次
*需要注意的是,如果数据有更新,也很可能还是会取到缓存中的数据。
QuerySet特点:
<1> 可迭代的
<2> 可切片
ORM缓存优化:
1、obj.exists() 如果queryset对象有数据,返回真 | 优化缓存
当取到匹配的数据就立即终止,防止大表的全部遍历
2、obj.iterator()
更迭代器一样,只能取一遍
当queryset非常巨大时,cache会成为问题:
处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法来获取数据,处理完数据就将其丢弃。
objs = Book.objects.all().iterator() # iterator()可以一次只从数据库获取少量数据,这样可以节省内存 for obj in objs: print(obj.name) #BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了 for obj in objs: print(obj.name) #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使 #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询。
总结:
queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能会造成额外的数据库查询。
四、神器的双下划线_ _
它:
可以在Book.objects.fitler()中filter中使用
可以在Book.objects.fitler().value()中values中使用
它:
可以用来实现多表连表查询(实现sql的inner join)
可以用来实现多种查询条件(id_ _lte id_ _lt id_ _gte id_ _gt)
五、对象查询,单表条件查询,多表条件关联查询
#--------------------对象形式的查找-------------------------- # 正向查找 ret1=models.Book.objects.first() print(ret1.title) print(ret1.price) print(ret1.publisher) print(ret1.publisher.name) #因为一对多的关系所以ret1.publisher是一个对象,而不是一个queryset集合 # 反向查找 ret2=models.Publish.objects.last() print(ret2.name) print(ret2.city) #如何拿到与它绑定的Book对象呢? print(ret2.book_set.all()) #ret2.book_set是一个queryset集合 #---------------了不起的双下划线(__)之单表条件查询---------------- # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 # # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and # # startswith,istartswith, endswith, iendswith, #----------------了不起的双下划线(__)之多表条件关联查询--------------- # 正向查找(条件) # ret3=models.Book.objects.filter(title='Python').values('id') # print(ret3)#[{'id': 1}] #正向查找(条件)之一对多 ret4=models.Book.objects.filter(title='Python').values('publisher__city') print(ret4) #[{'publisher__city': '北京'}] #正向查找(条件)之多对多 ret5=models.Book.objects.filter(title='Python').values('author__name') print(ret5) ret6=models.Book.objects.filter(author__name="alex").values('title') print(ret6) #注意 #正向查找的publisher__city或者author__name中的publisher,author是book表中绑定的字段 #一对多和多对多在这里用法没区别 # 反向查找(条件) #反向查找之一对多: ret8=models.Publisher.objects.filter(book__title='Python').values('name') print(ret8)#[{'name': '人大出版社'}] 注意,book__title中的book就是Publisher的关联表名 ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors') print(ret9)#[{'book__authors': 1}, {'book__authors': 2}] #反向查找之多对多: ret10=models.Author.objects.filter(book__title='Python').values('name') print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}] #注意 #正向查找的book__title中的book是表名Book #一对多和多对多在这里用法没区别
关系字段
Django 同样定义了一系列的字段来描述数据库之间的关联。
外键
- class ForeignKey(othermodel[, **options])
多对一关系。需要一个位置参数:与该模型关联的类。
参数
- ForeignKey.to_field
-
关联到的关联对象的字段名称。默认地,Django 使用关联对象的主键。
- ForeignKey.on_delete
当一个ForeignKey 引用的对象被删除时,Django 默认模拟SQL 的ON DELETE CASCADE 的约束行为,并且删除包含该ForeignKey的对象。例如,如果你有一个可以为空的ForeignKey,在其引用的对象被删除的时你想把这个ForeignKey 设置为空。
其中ON DELETE CASCADE的功能是在主数据删除的时候,从属数据一并删除,常用于强耦合关系中。
而ON DELETE SET NULL的功能是在主数据删除的时候,从属数据不会删除,只是将从属数据的关联属性字段设置成NULL,从而变为无主待关联数据,这个常用于弱耦合关系中。
on_delete的值:
- CASCADE
-
级联删除;默认值。
- PROTECT
-
抛出ProtectedError 以阻止被引用对象的删除,它是django.db.IntegrityError 的一个子类。
- SET_NULL
-
把ForeignKey 设置为null; null 参数为True 时才可以这样做。
ManyToManyField
- class ManyToManyField(othermodel[, **options])
一个多对多关联。要求一个关键字参数:与该模型关联的类,与ForeignKey 的工作方式完全一样,包括递归关系 和惰性关系。
- ManyToManyField.through
-
Django 会自动创建一个表来管理多对多关系。不过,如果你希望手动指定中介表,可以使用through 选项来指定Django 模型来表示你想要使用的中介表。
这个选项最常见的使用场景是当你想要关联额外的数据到多对多关联关系的时候。