ORM介绍
ORM概念
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
ORM在业务逻辑层和数据库层之间充当了桥梁的作用。
ORM总结
ORM只是一种工具,工具确实能解决一些重复,简单的劳动。这是不可否认的。
但我们不能指望某个工具能一劳永逸地解决所有问题,一些特殊问题还是需要特殊处理的。
但是在整个软件开发过程中需要特殊处理的情况应该都是很少的,否则所谓的工具也就失去了它存在的意义。
Django中的ORM
Model
在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型(model)映射到一个数据库表,
基本情况:
- 每个模型都是一个Python类,它是django.db.models.Model的子类。
- 模型的每个属性都代表一个数据库字段。
- 综上所述,Django为您提供了一个自动生成的数据库访问API,详询官方文档链接。
总结详细步骤:
1. 手动创建数据库
2. 在app/models.py里面写上一个类,必须继承models.Model这个类 (注意启动Django项目)
3. 在Django 项目的settings.py 里面 配置上数据库的相关信息
4. 在Django项目里的__init__.py里面写上 两句话 import pymysql pymysql.install_as_MySQLdb()
5. 给Django发布命令
1. python manage.py makemigrations # 相当于去你的models.py 里面看一下有没有改动
2. python manage.py migrate # 把改动翻译成SQL语句,然后去数据库执行
models.py --> Django翻译成SQL --> pymysql --> MySQL(4p)
总结一下:
models.py MySQL
类 对应 数据表
类的属性 对应 数据库里面的字段(列)
对象 对应 一行数据(一条数据)
ORM到底是什么? --> 对象关系映射
ORM操作
# 增 1. models.Tb1(表名).objects.create(c1='xx', c2='oo') # 增加一条数据,可以接受字典类型数据 **kwargs
models.Tb1(表名).objects.create(**{})
2.obj = models.Tb1(c1='xx', c2='oo')
obj.save()
# 查
models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议)
models.Tb1.objects.all() # 获取全部
models.Tb1.objects.filter(name='seven') # 获取指定条件的数据 ,不满足条件不报错,但是返回的结果是一个对象的列表
models.User.objects.filter().first() # 获取指定条件的数据 ,的第一个
models.User.objects.filter().last()# 获取指定条件的数据,的最后一个
models.Tb1.objects.exclude(name='seven') # 去除指定条件的数据 # 删 # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据 (不区分model对象和queryset对象) # 改 1.models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs
2. obj = models.Tb1.objects.get(id=1) #不建议使用,它是对id=1的整条记录都进行“更改”(除c1是对进行更改外,其余都是进行赋值) obj.c1 = '111'
obj.save()
单表查询API汇总
返回的是QuerySet对象 <1> all(): 查询所有结果【】 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象(queryset),返回的是一个列表,取一个值时需要用索引或切片, 什么时候使用filter()什么时候使用get() 当filter().后面继续使用的是Queryset对象时, 当get(). 后面跟的可以是字段或表名 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> values(*要显示的字段): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列 【】
l=[]
for obj in Book.objects.all():
temp={}
temp["title"]=obj.title
temp["id"]=obj.id
temp["publish__name"]=obj.publish.name # QuerySet() []
l.append(temp)
<6> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <7> order_by(*field): 对查询结果排序 正序 order_by(-*field): 对查询结果排序 反序 <8> reverse(): 对查询结果反向排序 <9> distinct(): 从返回结果中剔除重复纪录(必须是满足所有条件都重复) 返回bool值 <3> exists(): 如果QuerySet包含数据,就返回True,否则返回False 判断表里有没有数据用exists(),减少数据查询 返回数字的: <10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。 返回具体的数据(model)对象: <11> first(): 返回第一条记录 <12> last(): 返回最后一条记录 <13> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误
注意:一定区分Object与QuerySet的区别 !!!
QuerySet有update方法而Object默认没有。
单表查询之神奇的双下划线
models.Tb1.objects.filter(id__gt=1, id__lt=10) # 获取 id 大于1的值 且 id 小于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") # 获取name字段包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and 类似的还有:startswith,istartswith, endswith, iendswith date字段还可以: models.Class.objects.filter(first_day__year=2017) date字段还可以: models.Class.objects.filter(first_day__year=2017 查询某字段(sname)为空的: models.Class.objects.cname__isnull=True
ORM跨表查询
基于对象查询(sql:子查询) 一对多的关系 多对多的关系 一对一的关系 正向查询,按字段(外键):
反向查询,按表名小写_set:
基于Queryset和 __(sql:join语句):
一对多的关系 多对多的关系 一对一的关系
正向查询,按字段(外键)
反向查询,按表名小写
verbose_name
verbose_name: 可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Article model 中做一下更改: publish = ForeignKey(Blog, related_name='bookList'),那么接下来就会如我们看到这般: # 查询 人民出版社出版过的所有书籍(反向:表名_set) publish=Publish.objects.get(name="人民出版社") book_list=publish.bookList.all() # 与人民出版社关联的所有书籍对象集合
######################################################################
# print(type(obj._meta))# print(obj._meta.related_objects) #获取关联当前表(obj)的所有字段对象集合 from django.db.models.fields.reverse_related import ManyToOneRel for obj_related_field in obj._meta.related_objects: print(obj_related_field.field_name) # 关联字段对象的to_field的值 print(obj_related_field.related_name) # 反向查询别名,每张表中的名字唯一 print(obj_related_field.limit_choices_to) # 筛选条件(limit_choices_to=[条件],对被关联的表条件限制) print(obj_related_field.to) # 关联字段关联的表 print(obj_related_field.field.model._meta.model_name) # 关联字段对应的model
ORM 跨表查询 class Book(models.Model): title = models.CharField( max_length=32) publish=models.ForeignKey(to="Publish",to_field="id") authors=models.ManyToManyField(to='Author',related_name='bookList') class Publish(models.Model): name=models.CharField( max_length=32) class Author(models.Model): name=models.CharField( max_length=32) ad=models.OneToOneField("AuthorDetail") class AuthorDetail(models.Model): telephone=models.BigIntegerField() 基于对象查询(sql:子查询) 一对多的关系 (Publish--Book) 正向查询,按字段(外键): 查询python这本书的出版社所在的名称 book_obj=Book.objects.filter(title="python").first() #print(book_obj.publish.name) 反向查询,按表名小写_set: 人民出版社出版过的所有书籍名称 publish_obj=Publish.objects.filter(name="人民出版社出版").first() print(publish_obj.book_set.all()) for obj in publish_obj.book_set.all(): print(obj.title) 多对多的关系 正向查询,按字段: python这本书所有作者的名字 book_obj=Book.objects.filter(title="python").first() book_obj.authors.all() 反向查询,按表名小写_set: alex出版过的所有书籍名称 alex=Author.objects.filter(name="alex").first() alex.bookList.all() 一对一的关系 正向查询,按字段: 查询alex的手机号 alex=Author.objects.filter(name="alex").first() alex.ad.telephone 反向查询:按表名小写 以151开头的手机号的作者的名字 ad=AuthorDetail.objects.get(telephone__startswith="151") ad.author.name 基于Queryset和 __(sql:join语句): 正向查询,按字段(外键) 反向查询,按表名小写 一对多的关系 (Publish--Book) 查询python这本书的所在出版社的名称 Book.objects.filter(title="python").values("publish__name") #原理 for obj in Book.objects.filter(title="python"): temp={} temp["publish__name"]=obj.publish.name 人民出版社出版过的所有书籍名称 Publish.objects.filter(name="人民出版社出版").values("book__title") 多对多的关系 python这本书所有作者的名字 Book.objects.filter(title="python").values("authors__name") alex出版过的所有书籍名称 Author.objects.filter(name="alex").values("book__title") 一对一的关系 查询alex的手机号 Author.objects.filter(name="alex").values("ad__telephone") 以151开头的手机号的作者的名字 AuthorDetail.objects.filter(telephone__startswith="151").values("author__name") 扩展: 练习1: 查询python这本书的所在出版社的名称 Book.objects.filter(title="python").values("publish__name") Publish.objects.filter(book__title="python").values("name") 练习2: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 Book.objects.filter(authors__ad__telephone__startswith="151").values("title","publish__name") 聚合: 计算所有图书的平均价格: book.objects.all().aggregate(Avg("price")) 分组查询: 查询每一个出版社出版过的书籍个数 Publish.objects.annotate(Count("book__id")) select count(*) from publish group by id SELECT "app01_publish"."name", COUNT("app01_book"."id") AS "c" FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") GROUP BY "app01_publish"."id", "app01_publish"."name" publish: book: id name id title publish_id 1 A 1 python 1 2 B 2 go 1 3 C 3 linux 2 4 php 3 5 java 3 publish-book: nid publish_id publish_name book_id book_title publish_id 1 1 A 1 python 1 2 1 A 2 go 1 3 2 B 3 linux 2 4 3 C 4 php 3 5 3 C 5 java 3