django ORM
[toc]
5.ORM
5.1 ORM简介
- MVC或者MVC框架中包括一个重要的部分,就是ORM ,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
- ORM是“对象-关系-映射”的简称。(Object Relational Mapping,简称ORM)
- ORM执行的过程
- 类对象--->sql--->pymysql--->mysql服务端--->磁盘,orm其实就是将类对象的语法翻译成sql语句的一个引擎
ORM与原生SQL对比
5.2 ORM操作
5.2.1 ORM连接mysql
这里先来一个orm连接mysql并创建一张表的示例
第一步、修改settings配置文件,配置mysql相关信息
#先注释默认项
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '数据库名',
'HOST': '数据库IP',
'PORT': '数据库端口',
'USER': '用户',
'PASSWORD': '密码'
}
}
第二步、在项目目录下的同名目录下的__init__.py
文件中写上以下内容,来指定pymysql作为连接客户端
import pymysql
pymysql.install_as_MySQLdb()
第三步、在应用程序目录下面的models.py文件中写对应的类,这里为创建一张表
from django.db import models
#这里表示创建一个userinfo表,需要注意的是,django在创建表的时候会把表名小写并重命名为 应用程序_userinfo
class UserInfo(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=10)
password = models.CharField(max_length=32)
第四步: 执行数据库同步指令,在终端中执行,执行的路径是django项目下
#在migrations文件夹下面生成记录文件
python3 manage.py makemigrations
#执行记录文件
python3 manage.py migrate
可以看到,我们自定义的表已经创建完成了,但是发现多了好多其他的表,那这些表是从哪来的呢,这些是django从settings文件中循环读取INSTALLED_APPS下的所有子项而默认创建的表
表结构
5.2.2 单表操作
5.2.2.1 增
应用程序的models.py文件中已经定义了创建一张表的语句
urls文件
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]
views文件
from django.shortcuts import render,HttpResponse
from app01 import models
#方式1
def index(request):
obj = models.UserInfo(
username='小明',
password='123'
)
obj.save()
return HttpResponse('ok')
#方式2
def index(request):
models.UserInfo.objects.create(
username='小颖',
password='666'
)
return HttpResponse('ok')
接下来启动django项目,浏览器访问我们指定的127.0.0.1:8000/index
执行以上任意一种方式都可以插入数据
5.2.2.2 删
views文件
def index(request):
#删除UserInfo表中id值为1的值
models.UserInfo.objects.filter(id=1).delete()
return HttpResponse('ok')
浏览器访问127.0.0.1/index即可成功执行语句
可以看到,id为1的字段已经被删除
5.2.2.3 改
views文件
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
# 方式1
models.UserInfo.objects.filter(id=2).update(
username='abc',
password='abc',
)
# 方式2
# obj = models.UserInfo.objects.filter(id=2)[0]
# obj.username = 'ggg'
# obj.password = 'ggg'
# obj.save()
return HttpResponse('ok')
浏览器访问127.0.0.1/index
可以看到修改已经生效
批量创建
views文件
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
list_obj = []
for i in range(6):
obj = models.UserInfo(
username='name%s' %i,
password='pwd%s' %i,
)
list_obj.append(obj)
print(list_obj)
models.UserInfo.objects.bulk_create(list_obj)
return HttpResponse('ok')
print(list_obj)返回的结果如下
[<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]
浏览器访问127.0.0.1/index
可以看到已经批量插入了数据
update_or_create 有就更新,没有就创建
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
a,b = models.UserInfo.objects.update_or_create(
username='name0',
defaults={
'id': 20,
'password': 'abcdef',
}
)
print(a) #当前更新后的model对象,或者是你新增的记录的model对象
print(b) #新增就是True,查询就False
return HttpResponse('ok')
#a返回的结果
UserInfo object
#b返回的结果
True
5.2.2.4 查
最简单的查询
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
ret = models.UserInfo.objects.filter(id=1)
print(ret) # <QuerySet [<UserInfo: UserInfo object>]> -- []
obj = ret[0]
print(obj.id, obj.username)
return HttpResponse('ok')
表app01_userinfo内容如下
print(ret)结果如下
<QuerySet [<UserInfo: UserInfo object>]>
print(obj.id, obj.username)执行后结果如下
1 aaa
查询非常重要的13种方法
1 all() 查询所有结果,结果是queryset类型
views文件
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
ret = models.UserInfo.objects.all()
print(ret)
return HttpResponse('ok')
#print(ret)结果如下
<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
现在我们想看到的是数据库中的数据,需要在models文件中我们创建的UserInfo中写一个类的属性
class UserInfo(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=10)
password = models.CharField(max_length=32)
#在models文件中写上这个属性后就能在all()方法中返回数据而不是对戏那个
def __str__(self):
return self.username
#结果如下
<QuerySet [<UserInfo: aaa>, <UserInfo: bbb>]>
2 get() 只能返回一个数据,没有或者数据多就报错,不是queryset类型,是行记录对象
例如,查询一个表中密码为aaa的数据,如果这个表中只有一个用户的密码是aaa,则可以查询成功,如果这个表中有多个用户的密码是aaa这个时候就会报错并且这个表中如果没有用户的密码是aaa同样会报错
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
ret = models.UserInfo.objects.get(password='aaa')
print(ret)
return HttpResponse('ok')
表app01_userinfo内容如下
浏览器访问127.0.0.1/index
此时返回的结果是可以成功查询的
现在修改表内容如下
再次执行以上代码,查询表中密码为aaa的数据,此时会报错
修改代码为查询表中密码为bbb的数据,同样会报错
get两个报错,但是get请求返回的结果是model对象
#1.UserInfo matching query does not exist. 没有查到的报错
#2 get() returned more than one UserInfo -- it returned 11! 结果多了,不行!
3 filter() 查询数据,返回值是queryset类型
views文件
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
ret = models.UserInfo.objects.filter(password='bbb')
print(ret)
return HttpResponse('ok')
filter查询表中密码为bbb的数据,虽然表中结果没有,但是不会像get报错
print(ret)结果如下
<QuerySet []>
filter查询表中密码为aaa的数据,表中密码为aaa的数据有2条,filter不会像get一样报错
<QuerySet [<UserInfo: aaa>, <UserInfo: bbb>]>
4 exclude() 排除,返回值是queryset类型
现有app01_book表如下
查询所有数据,排除bid为4的数据
urls文件
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]
views文件
from django.shortcuts import render,reverse,redirect,HttpResponse
from app01 import models
def index(request):
#查询bid不为4的数据,这里还可以写多个排除条件,以逗号分隔
ret = models.Book.objects.exclude(bid=4)
print(ret)
return HttpResponse('ok')
models文件
class Book(models.Model):
bid = models.AutoField(primary_key=True)
bname = models.CharField(max_length=20)
price = models.DecimalField(max_digits=6,decimal_places=2)
publish_date = models.DateField(auto_now_add=False)
publish = models.CharField(max_length=20)
def __str__(self):
return self.bname
浏览器访问127.0.0.1/index,返回结果如下,bid为4的隔壁老王的故事没有返回
<QuerySet [<Book: 1-Linux从入门到放弃>, <Book: 2-python从入门到放弃>, <Book: 3-mysql之从删库到跑路>, <Book: 5-放开那个女孩>, <Book: 6-成为富翁的秘密>]>
5 order_by() queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值是queryset类型
按照bid倒序排序,在bid前加个-号即可
viwes文件
def index(request):
ret = models.Book.objects.all().order_by('-bid')
print(ret)
return HttpResponse('ok')
浏览器反问127.0.0.1/index,返回结果如下,结果是倒序
<QuerySet [<Book: 6-成为富翁的秘密>, <Book: 5-放开那个女孩>, <Book: 4-隔壁老王的故事>, <Book: 3-mysql之从删库到跑路>, <Book: 2-python从入门到放弃>, <Book: 1-Linux从入门到放弃>]>
order_by()中加多个条件说明
#这段代码的意思是按照id倒叙排序,然后再按照id相同的数据进行价格升序排序
models.Test.objects.all().order_by('-id','money')
现有表app01_test如下
先按照id进行倒叙排序
ret = models.Test.objects.all().order_by('-id')
print(ret.values())
返回结果如下
<QuerySet [{'id': 3, 'name': '3-哈哈', 'money': 8}, {'id': 3, 'name': '3-大强', 'money': 80}, {'id': 3, 'name': '3-呵呵', 'money': 800}, {'id': 2, 'name': '2-小颖', 'money': 100}, {'id': 1, 'name': '1-小明', 'money': 10}]>
再加一个条件进行排序,先根据id相同的进行倒序排序,然后再根据money升序排序
ret = models.Test.objects.order_by('-id','money')
print(ret.values())
返回结果如下
<QuerySet [{'id': 3, 'name': '3-大强', 'money': 80}, {'id': 3, 'name': '3-呵呵', 'money': 800}, {'id': 3, 'name': '3-哈哈', 'money': 8}, {'id': 2, 'name': '2-小颖', 'money': 100}, {'id': 1, 'name': '1-小明', 'money': 10}]>
6 reverse() queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型
以例5中app01_test表为例
⚠️直接进行reverse进行反向排序是不生效的,必须先进行分组
ret = models.Test.objects.all().reverse()
返回结果如下,不分组进行反向排序是不生效的
<QuerySet [{'id': 1, 'name': '1-小明', 'money': 10}, {'id': 2, 'name': '2-小颖', 'money': 100}, {'id': 3, 'name': '3-大强', 'money': 80}, {'id': 3, 'name': '3-呵呵', 'money': 800}, {'id': 3, 'name': '3-哈哈', 'money': 8}]>
先进行分组,然后再进行反向排序才能生效
ret = models.Test.objects.all().order_by('id').reverse()
返回结果如下
<QuerySet [{'id': 3, 'name': '3-大强', 'money': 80}, {'id': 3, 'name': '3-呵呵', 'money': 800}, {'id': 3, 'name': '3-哈哈', 'money': 8}, {'id': 2, 'name': '2-小颖', 'money': 100}, {'id': 1, 'name': '1-小明', 'money': 10}]>
7 count() queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量
以例5中app01_test表为例
ret = models.Test.objects.all().count()
print(ret)
返回结果为5,因为app01_test表中有5条记录
8 first() queryset类型的数据来调用,返回第一条记录,得到的都是model对象,不是queryset
以例5中app01_test表为例
ret = models.Test.objects.all().first()
print(ret)
#models文件表的类中需要写如下代码
class Test(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
money = models.IntegerField()
def __str__(self):
return self.name
返回结果为1-小明