python学习笔记-django的ORM
一、ORM了解
ORM即对象关系映射,使开发者可以使用面向对象的方式操作数据库,而不需要直接编写复杂的SQL语句。
django数据库中,表与表的关联,可分为一对一,一对多,多对多
django中常用的一对多,创建时用外键关联。一对一是用unque关键字,多对多可以理解是一对多,外加关联表。
django默认支持sqlite,mysql,oracle,postgresql数据库
1、django默认支持sqlite的数据库,默认自动sqlite的数据库驱动,
引擎名称:django.db.backends.sqlite3
mysql:引擎名称:django.db.backends.mysql
2、mysql驱动程序
MySQLdb(mysql python)
mysqlclient
MySQL
PyMySQL(纯python的mysql驱动程序)
3、在django的项目中会默认使用sqlite数据库,在settings里有如下设置

使用sqlite数据库时没有配置数据库名,创建的表是在默认的数据库,这种情况只限sqlite数据库。mysql数据库要指定数据库名
DATABASWS={
'default':{
'ENGINE':'django.db.backends.mysql',
'NAME':'Django_ORM',
'USER':'root',
'PASSWORD':'123456',
'HOST':'', #数据库主机,默认为localhost
'PORT':'3306'
}
}
4、创建数据表实例
class Book(models.Model):
name=models.CharField(max_length=20)
price=models.IntegerField()
pub_date=models.DateField()
5、执行创建表的命令
python manage.py makemigrations
python manage.py migrate
备注:使用原生的SQL和使用ORM的差别
1、初学者使用ORM,熟练的更了解查询性能,用原生SQL多,原生SQL能处理复制场景
2、ORM数据库搬迁时方便,不需要做太多改动。
二、ORM对单表的增删改查
案例使用mysql数据库,配置setting文件后。创建表,model文件编辑如下
from django.db import models #Create your models here. class Book(models.Model): name=models.CharField(max_length=20) price=models.IntegerField() pub_date=models.DateField() publish=models.ForeignKey("Publish",on_delete=models.CASCADE) #on__delete没有会报错 authors=models.ManyToManyField("Author") def __str__(self): return self.name class Publish(models.Model): name=models.CharField(max_length=32) city=models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField(default=20) def __str__(self): return self.name
安装驱动,django2.0以上版本用的是mysqlclient 用pip安装
在django2.0后,定义外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题,不然会报错
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
执行同步建表命令时,可能出现报错,根据提示调整(可能是驱动问题或mysql版本问题),本次执行没有报错
1、表数据增加
方式一
b=Book(name='python',price=99,author='steven',pub_date='2017-12-12')
b.save()
方式二
Book.objects.create(name='python',price=99,author='steven',pub_date='2017-12-12')
create可以传字典对象,参数**dic,可以批量创建,写循环方式创建
2、表数据修改
方式一
Book.objects.filter(author='yuan').update(price=999)
方式二
b=Book.objects.get(author='oldboy') #这里的get拿到的是一个实例对象,filter拿到的是Queryset对象
b.price=100
b.save()
3、表数据删除
Book.objects.filter(author='yuan').delete()
4、表数据查询
book_list=Book.objects.all()
book_list=Book.objects.all()[::2] #切片
book_list=Book.objects.filter()
book_list=Book.objects.first() #first、last、get取到的都是一个实例对象
book_list=Book.objects.last()
book_list=Book.objects.get() #只能取出一条记录时,才不报错
其他常用方法
exclude() 排除之外的
对查询结果进一步处理
book_list=Book.objects.filter(author='yuan').value('name') #value拿某个具体字段,字典的集合。(可以传多个字段条件,如name,price)
book_list=Book.objects.filter(author='yuan').value_list('name') #返回的是一个元组序列
distinct() 去重
book_list=Book.objects.all().value('name').distinct()
count() 计数
order_by(*field) 对查询结果排序
reverse() 反向排序
exists() 是否存在
万能的__,(模糊查询)
查price>50的
book_list=Book.objects.filter(price__gt=50).values('name','price') #__后可跟更多字母条件,gt是大于,lt是小于。
查name包含P
book_list=Book.objects.filter(name__icontains='P').values('name','price') #包含P的,不区分大小写的数据
示例:路由urls和调用的操作方法views
path(r'data/',views.index), path(r'create/',views.create), path(r'modify/',views.modify), path(r'delete/',views.delete), path(r"querydb/",views.querydb)
def create(req): #方式一 # p=Publish(name="南方出版社",city="广州") # p.save() # #方式二 # Publish.objects.create(name="新华出版社",city="重庆") aut=[{"name":"张飞","age":19},{"name":"李四","age":30},{"name":"李白","age":35}] for a in aut: Author.objects.create(**a) return HttpResponse("新增成功") def modify(req): #方式一 # Author.objects.filter(name="张三").update(age=20) #方式二 a=Author.objects.get(name="张飞") a.age=26 a.save() return HttpResponse("修改成功") def delete(req): Author.objects.filter(name="李四").delete() return HttpResponse("删除成功") def querydb(req): ret=Author.objects.all() #<QuerySet [<Author: 张三>, <Author: 张飞>, <Author: 李白>]> ret=Author.objects.filter(name="李白")#<QuerySet [<Author: 李白>]> ret = Author.objects.first() #张三 ret=Author.objects.last() #李白 ret = Author.objects.get(age=35) #李白 ret = Author.objects.exclude(age=35) #<QuerySet [<Author: 张三>, <Author: 张飞>]> ret = Author.objects.all().count() #3 ret = Author.objects.all().order_by("age").reverse() #<QuerySet [<Author: 李白>, <Author: 张飞>, <Author: 张三>]> ret = Author.objects.filter(name="李白").exists() #True #模糊查询 ret=Author.objects.filter(age__gt=32)#<查询年龄大于32的作者。QuerySet [<Author: 李白>]> ret = Author.objects.filter(age__gt=32).values("name","age") #values设置显示的字段范围。<QuerySet [{'name': '李白', 'age': 35}]> ret = Author.objects.filter(name__icontains="张").values("name", "age") #查询名字包含”张“的作者,<QuerySet [{'name': '张三', 'age': 20}, {'name': '张飞', 'age': 26}]> print(ret) return HttpResponse("success")
查询数据库验证表数据操作结果正确

三、多表操作
1、一对多
新增数据
#方式一:# publish_id=1
Book.objects.create(name="linux运维", price=77, pub_date="2026-08-12", publish_id=1)
#方式二:
publish_obj = Publish.objects.filter(name="人民出版社")[0]
Book.objects.create(name="linux基础", price=55, pub_date="2026-08-13", publish=publish_obj)

查询数据
#方式一
pub_obj = Publish.objects.filter(name="人民出版社")[0]
ret = Book.objects.filter(publish=pub_obj).values("name", "price")
print(ret)
#方式二
#先找到publish对象
pub_obj = Publish.objects.filter(name="人民出版社")[0]
#通过pub_obj找到关联的book对象的集合
print(pub_obj.book_set.all().values("name", "price"))

注意:建表时,一对多,外键一定是建在多的一方(这里的book)
Django会自动在创建表的时候,把外键的名称后加id。如book的外键publish,创建的表字段是publish_id
#方式三
#查出版社是人民出版社的书籍名称和价格
ret = Book.objects.filter(publish__name = "人民出版社").values("name", "price")
print(ret)
#查书籍名称是python的出版社名字
ret2 = Publish.objects.filter(book__name="python").values("name")
print('ret2:',ret2)
#查书籍名称是python的出版社名字
ret3 = Book.objects.filter(name="python").values("publish__name")
print("ret3:",ret3)
#查北京出版社出的书
ret4 = Book.objects.filter(publish__city="北京").values("name")
print("ret4:",ret4)
#查询2026年上半年出版了书籍的出版社名称
ret5 = Book.objects.filter(pub_date__lt="2026-07-01", pub_date__gt="2026-01-01").values("publish__name")
print("ret5:",ret5)
return HttpResponse("success")

2、多对多
2.1、创建多对多关系
authors=models.ManyToManyField("Author")
*在Book写字段方式创建,python自动创建第三张关联表

2.2、创建多对多映射,给指定书籍新增所有作者关联
def manytomany(req): #增加多对多关系映射,给书籍增加所有作者 book_obj = Book.objects.get(id=4) author_objs = Author.objects.all() book_obj.authors.add(*author_objs) return HttpResponse("success")
执行结果,正确创建了记录,查看第三张表

只增加一个作者
#增加一个作者 book_obj = Book.objects.get(id=3) author_obj = Author.objects.get(id=5) book_obj.authors.add(author_obj)
执行结果,创建了一条记录

2.3、多对多查询
#正向查找 book_obj = Book.objects.get(id=4) print(book_obj.authors.all()) print(type(book_obj.authors.all())) #反向查找 author_obj = Author.objects.get(id=5) print(author_obj.book_set.all())
结果

2.4、删除多对多
#删除多对多关系 book_obj = Book.objects.get(id=4) book_obj.authors.remove(6) #删除authors_id=2的关系 author_objs = Author.objects.all() book_obj.authors.remove(*author_objs) #删除书籍所有的作者关联
结果

注意:
多对多没有直接赋值的方式创建多对多关系
多对多第三张表是自动创建的
创建的多对多关系有重复时会去掉重复
2.5、自动创建和手动创建第三张表的对比
不用ManyToMany自己手动创建第三张表时(Book_Author)
这时用直接赋值创建
Book_Author.objects.create(book_id=2,author_id=3)
查询(比较麻烦,不常用)
obj=Book.objects.get(id=2)
print(obj.book_author_set.all()[0].author())
示例:(自己创建第三张表)查询作者是bob的书名,价格
ret=Book.objects.filter(book_author__author__name='bob').values("name","price")
示例2:(ManyToMany)时查询相同数据
ret2=Book.objects.filter(author__name="bob").values("name","price")
四、聚合查询和分组查询
1、聚合查询
示例:
def aggrequery(req): from django.db.models import Avg,Min,Sum,Max,Count #单表: ret = Book.objects.all().aggregate(Avg("price")) ret2 = Book.objects.all().aggregate(Sum("price")) print("书籍平均价格",ret,",价格之和",ret2) #多对多场景查询 #查询关羽写的书,总的价格 ret3 = Book.objects.filter(authors__name='关羽').aggregate(Sum("price")) # 结果格式是字典{"price_sum":128},可以自己设置键的名称 ret4 = Book.objects.filter(authors__name='关羽').aggregate(yuchang_money=Sum("price")) print("关羽写的书总价格:",ret3) print(ret4) return HttpResponse("success")
结果:

2、分组查询
示例:
#分组查询 #查询每个作者写的书,价格之和 ret5 = Book.objects.values("authors__name").annotate(Sum("price")) #查询每个出版社最低的图书价格 ret6 = Publish.objects.values("name").annotate(Min("book__price")) print(ret5) print(ret6)
结果:

结果存在一条作者名是none的记录,是因为有的书籍在多对多关系表中没有关联作者。
3、查询中的计算(F查询和Q查询)
示例:
#算术运算和逻辑运算 #使用逗号标识多个条件与查询 (示例get没查询到符合条件的结果时,运行报错了) ret7=Book.objects.get(name="西游记", price=50) print(ret7) #把所有书的价格加10,使用F查询 from django.db.models import F, Q Book.objects.all().update(price=F("price") + 10) #使用多个条件进行或查询,使用Q查询 ret8=Book.objects.filter(Q(price=65) | Q(name="春秋")) print(ret8) #使用~进行非运算查询 ret9=Book.objects.filter(Q(price=65) | ~Q(name="春秋")) print(ret9) #扩展:关键字和Q混合用 ret10 = Book.objects.filter(Q(name__contains="p")) ret11 = Book.objects.filter(Q(name="p"), price=60) # Q查询语句要写在前面 print(ret10) print(ret11)
结果:

数据表

4、总结
【ORM的querySet集合对象的特性】
1、QuerySet是在用到的时候才去数据库查询,惰性机制。(提高网站性能)
用到的场景,if for print语句.会查数据库
2、Django给queryset数据类型加了缓存,执行一次后,再次使用不会重复查询数据库,从缓存中读取
可以通过执行两次for循环,检查sql数据打印次数
3、exists()会查数据库,但不会把数据放在缓存
if ret.exits(): print("OK")
4、当queryset非常大时,会让缓存引发问题,极大消耗内存
解决方法:查询结果使用iterater()
ret=ret.iterator() #变成迭代器对象 for i in ret: print(i.name)
使用exists()和iterator()可以优化程序对内存的使用,不过,它们不会生成queryset cache。结果不能重复使用,下次使用要重新查数据库,造成额外的数据库查询。
浙公网安备 33010602011771号