一、基本概念
DRF(Django Rest Framework)是可以快速基于Restful开发得Django应用得插件,功能非常多,被广泛应用。
所谓Restful风格就是不在用户请求的URL当中说明 “操作动作(create,delete,put)”。而是直接请求资源,通过不同的http方法来做对应的操作。
比如:
GET 127.0.0.1:8000/app1/ 获取app1应用的所有资源
POST 127.0.0.1:8000/app1/ 新增app1响应的数据
GET 127.0.0.1:8000/app1/1 获取app1应用下主键为 1 的资源
PUT 127.0.0.1:8000/app1/1 修改app1应用下主键为 1 的资源
delete 127.0.0.1:8000/app1/1 删除app1应用下主键为 1 的资源
二、安装
pip install djangorestframework
注册:
在settings.py文件中进行注册.注册之后呢,在使用浏览器访问的时候,返回的结果会渲染成html页面
INSTALLED_APPS = [
......
'rest_framework',
]
三、DRF的视图类
django的视图类: View
DRF的视图类: APIView
View是APIView的父类,所以这两个视图类的用法是一样的
1.APIView
1.1 创建应用
django-admin startapp app1
1.2 配置总路由
编辑项目目录下的总urls.py文件
urlpatterns = [
path('app1/',include('app1.urls')),
]
1.3 新建分布式路文件
在app1应用目录下新建urls.py文件,内容如下
from django.urls import path
from .views import *
urlpatterns = [
path('',test.as_view()),
]
1.4 新建视图函数
from rest_framework.views import APIView,Response
class test(APIView):
def get(self,request):
return Response({"message": "访问GET方法成功"})
def post(self,request):
return Response({"message": "访问POST方法成功"})
1.5 验证
分别使用GET方法和POST方法请求以下连接
http://127.0.0.1:8000/app1/
2.APIView GET请求
request.query_params: 获取GET请求所有参数
request.query_params.get("name") :获取get请求中某个key的值
视图函数:
from rest_framework.views import APIView,Response
class test(APIView):
def get(self,request):
print(request.query_params)
print(request.query_params.get("name"))
return Response({"message": "访问GET方法成功"})
发送请求验证
http://127.0.0.1:8000/app1/?name=zhangsan&password=123
结果如下:
<QueryDict: {'name': ['zhangsan'], 'password': ['123']}>
zhangsan
3.APIView POST请求
request.data.get() : 获取post请求的数据
视图函数如下:
from rest_framework.views import APIView,Response
class test(APIView):
def post(self,request):
print(f'POST的数据 = {request.data.get("user")}')
print(f'POST的数据 = {request.data.get("password")}')
return Response({"message": "访问POST方法成功"})
发送POST请求
http://127.0.0.1:8000/app1/
form-data 如下:
user:admin
password: 123123
结果如下:
POST的数据 = admin
POST的数据 = 123123
4.DRF的Response
DRF封装了自己的Response,对django的Httpsponse进行了封装和增强,可以直接对字典进行序列化。代码如下:
from rest_framework.response import Response
data = {
"usernmae": "张三",
"age": 100
}
class test(APIView):
def get(self,request):
return Response(data)
使用get请求访问
http://127.0.0.1:8000/app1/
返回结果如下:
{
"usernmae": "张三",
"age": 100
}
四、DRF序列化
1.概念
1.1 序列化
将内存中对象存储下来,把它变成一个个字节。
简单来讲: 数据结构–>二进制
举例:python中的json.dumps()就是序列化函数。将python中的字典转换成json格式的字符串的过程就是序列化
1.2.反序列化
将文件得一个个字节恢复成内存中得对象
简单来讲: 二进制–>数据结构
举例:python中的json.loads()就是反序列化,将json字符串转换成python的中字典的过程称为反序列化。
1.3 DRF序列化
在DRF中:model类–>字典–>JSON字符串(字符序列)
django中得DRF主要是配置model类来使用得。他主要是将"model类得实例" 转化为 “字典”。再由json模块转换为json字符串.
1.4 DRF反序列化
在DRF中:JSON字符串–>字典–>model类(入库持久化)
浏览器提交过来得数据,DRF做数据校验,在入库
2.序列化器
1.创建数据库model类
!!! 注意 !!!:这里定义模型类的时候,不要定义id字段,django在迁移的时候,会自动生成id字段,并且是primary_key 和自增长的字段。
如果写了,在后边写PUT方法的时候,会有一个报错:如果POST的数据中不传递id 会报错,说ID是必填字段。如果填写了又说ID是存在的。
在应用app1的models.py中编写mode类
from django.db import models
class student(models.Model):
class Meta:
db_table = 'my_student'
name = models.CharField(max_length=20)
age = models.IntegerField()
进行迁移
python manage.py makemigrations
python manage.py migrate
查看生成的表结构
mysql> desc my_student;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| age | int(11) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2.插入内容
INSERT INTO my_student VALUES (0,'zhangsan',20),(0,'lisi',21),(0,'wangwu',20),(0,'xiaoqiang',26),(0,'xiaoming',22);
mysql> select * from my_student;
+----+-----------+-----+
| id | name | age |
+----+-----------+-----+
| 1 | zhangsan | 20 |
| 2 | lisi | 21 |
| 3 | wangwu | 20 |
| 4 | xiaoqiang | 26 |
| 5 | xiaoming | 22 |
+----+-----------+-----+
5 rows in set (0.00 sec
3.创建序列化器
在app1的应用目录下创建serializers.py文件.文件名是可以自定义的。
DRF提供了一个类:serializers.ModelSerializer。这个类就帮我们做了序列化器和model字段的一一对应
这一步创建序列化器才是在序列化过程中最重要的的步骤。
from .models import *
from rest_framework import serializers
class student_serializers(serializers.ModelSerializer):
class Meta:
# 这是对student 类进行序列化
model = student
# 序列化所有字段
fields = '__all__'
3.序列化
注意:单行序列化 获取数据库数据时使用的是objects.get()
多行序列化 获取数据库数据时使用的是objects.filter(),并且做数据转换的时候必须使用many=True参数。
编写路由
编辑app1应用下的路由文件urls.py。
这里使用了两个函数test和testDetail
from django.urls import path
from .views import *
urlpatterns = [
# 这个路由是为了符合restful风格的接口,get所有资源准备的路由.
path('',test.as_view()),
# 这个路由是为了对单个资源进行操作的路由.
# 在路由中也定义了 用来定位资源的变量: id
path('<int:id>/',testDetail.as_view())
]
1 单行序列化
编写app1应用下视图函数文件views.py
from rest_framework.views import APIView,Response
from .models import *
from .serializers import *
class testDetail(APIView):
def get(self, request,id):
# 获取单行数据库数据
res = student.objects.get(pk=id)
# 使用自定义序列化器 对结果进行序列化,并且使用.data返回序列化后的数据
ser_data = student_serializers(instance=res).data
# 将最后的结果序列化为json返回给用户
return Response(ser_data)
用户使用GET请求
http://127.0.0.1:8000/app1/2
结果如下:
{
"id": 2,
"name": "lisi",
"age": 21
}
2 多行序列化
依然是app1下视图函数文件views.py文件
from rest_framework.views import APIView,Response
from .models import *
from .serializers import *
# 这个函数和上边不是一个函数
class test(APIView):
def get(self,request):
# 获取数据库 符合条件的多行数据集。这里的参数应该是用户传递过来的,这里就直接写了
res = student.objects.filter(age__gt=20)
# 对多行数据集合进行序列化
ser_data = student_serializers(instance=res,many=True).data
# 将数据序列化后返回给用户
return Response(ser_data)
结果如下:
[
{
"id": 2,
"name": "lisi",
"age": 21
},
{
"id": 4,
"name": "xiaoqiang",
"age": 26
},
{
"id": 5,
"name": "xiaoming",
"age": 22
}
]
4、反序列化
1.新增数据(POST)
视图函数如下:
from rest_framework.views import APIView,Response
from .models import *
from .serializers import *
class test(APIView):
def get()
......
# 新增POST方法
def post(self,request):
# 将用户post的请求的数据传递给序列化器
ser_data = student_serializers(data=request.data)
# 序列化器对 用户提交的数据进行合法校验
if ser_data.is_valid():
ser_data.save()
return Response("数据写入成功")
用户访问路由,使用POST方法:
http://127.0.0.1:8000/app1/
用户POST数据为:
{
"name": "zhangwuji",
"age": 20
}
查看数据库,数据已经添加成功
mysql> select * from my_student;
+----+-----------+-----+
| id | name | age |
+----+-----------+-----+
| 1 | zhangsan | 20 |
| 2 | lisi | 21 |
| 3 | wangwu | 20 |
| 4 | xiaoqiang | 26 |
| 5 | xiaoming | 22 |
| 6 | zhangwuji | 20 |
+----+-----------+-----+
6 rows in set (0.00 sec)
2.更新数据(PUT)
class testDetail(APIView):
def get(self,request,id):
pass
# 新增put方法
def put(self,request,id):
query_data = student.objects.get(pk=id)
ser_save_data = student_serializers(instance=query_data, data=request.data)
if ser_save_data.is_valid():
ser_save_data.save()
return Response("数据修改成功")
else:
print(ser_save_data.errors)
return Response("数据修改失败")
使用PUT方法访问:
PUT http://127.0.0.1:8000/app1/6/
将zhangwuji改为zhangsanfeng,提交数据为:
{
"name": "zhangsanfeng",
"age": 20
}
查看结果修改成功
mysql> select * from my_student;
+----+--------------+-----+
| id | name | age |
+----+--------------+-----+
| 1 | zhangsan | 20 |
| 2 | lisi | 21 |
| 3 | wangwu | 20 |
| 4 | xiaoqiang | 26 |
| 5 | xiaoming | 22 |
| 6 | zhangsanfeng | 20 |
+----+--------------+-----+
6 rows in set (0.00 sec)
3.删除数据
class testDetail(APIView):
def get(self,request,id):
pass
def put(self,request,id):
pass
# 新增delete方法
def delete(self,request,id):
try:
query_data = student.objects.get(pk=id)
query_data.delete()
except Exception:
return Response("数据删除失败")
else:
return Response("数据删除成功")
使用delete方法请求.无需post数据。
删除id为 6 的数据
http://127.0.0.1:8000/app1/6/
5.总结
这里一共两个函数,5个方法。增删改查查
class test(APIView):
# 获取所有资源
def get()
# 添加一个资源
def post()
class testDetail(APIView):
# 获取单个资源
def get()
# 修改单个资源
def put()
#删除单个资源
def delete()
如下图:
五、通用视图类
1.视图类的缺点
使用了APIview确实有些了增强的部分,但是如果有多个应用,或者一个应用里多个业务类,那就会有很多的重复代码。
重复代码指的是:
1.每一个业务类当中都要重复写get、post方法
2.每一个方法当中都要重复写 查询集合,序列化器、数据校验、数据保存等
于是:DRF又提供了genericAPIview和mixins
2.GenericAPIView
GenericAPIView主要是提供了两个变量,这两个变量的名称是固定写法。因为源码里是这么写的。这两个变量主要是提供给Mixins类使用的。
from rest_framework.generics import GenericAPIView
1.queryset: 得出查询数据库数据的集合
2.serializer_class: 指定序列化器
3.mixins类
在View和APIView中,我们都需要手写了get、put、post等方法,来处理增删改查查的数据。
DRF中提供了这5个类,和get、put、delete、get、post的功能一样,而且比自己写的处理数据逻辑更严谨
ListModelMixin: 查所有
RetrieveModelMixin:查单条
CreateModelMixin:新增
UpdateModelMixin:更新
DestroyModelMixin:删除
4.组合使用
4.1 总路由
urlpatterns = [
path('app1/',include('app1.urls')),
]
4.2 子路由
from django.urls import path
from .views import *
urlpatterns = [
path('',test.as_view()),
# 这里的变量名必须叫做pk. 前边的视图函数可以自定义,参数也可以自定义,所以这里的路由变量也可以自定义。
# 但是现在用的是GenericAPIView类,源码当中定义的叫做pk,所以这里必须叫做pk
path('<int:pk>',testDetail.as_view())
]
4.3 model类和序列化器
model类和序列化器没有变化,依然使用上边"四"中的配置即可
4.4 视图函数
编辑views.py文件
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import (
ListModelMixin,RetrieveModelMixin,
CreateModelMixin,UpdateModelMixin,DestroyModelMixin
)
from .models import *
from .serializers import *
class test(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = student.objects.all()
serializer_class = student_serializers
# 这里之所以要这样赋值,根本原因是APIView和View都是通过dispatch方法,根据方法的名称进行的请求分发。
# 所以DRF提供的5个处理数据的方法,最终名称还是要和put、post等5个方法的名称对应上。否则dispatch方法无法找到视图类
get = ListModelMixin.list
post = CreateModelMixin.create
class testDetail(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = student.objects.all()
serializer_class = student_serializers
get = RetrieveModelMixin.retrieve
put = UpdateModelMixin.update
delete = DestroyModelMixin.destroy
4.5 测试
DRF默认不支持批量新增和批量修改
1.get所有资源 http://127.0.0.1:8000/app1/
2.get单个资源 http://127.0.0.1:8000/app1/2
3.delete单个数据 http://127.0.0.1:8000/app1/9
4.post单个数据 http://127.0.0.1:8000/app1/
数据如下:
{
"name": "zhangsanfeng",
"age": 20
}
5.put 单个数据 http://127.0.0.1:8000/app1/2
数据如下:
{
"name": "xiaoli",
"age": 25
}
六、concreteAPIView(混凝土)
在 五 中我们需要手动继承和组合genenicAPIView和mixins类。genenicAPIView和minxinx提供的功能类进行自由组合。这样继承的类相对来说较多。
因此DRF又提供了写好的genicAPIview和mixIn的组合类。如果不需要自定义的化,可以使用提前定义好的view类
1.组合方式
concreteAPIview | 组合方式 | 方法 | 功能 |
---|---|---|---|
CreateAPIView | GenericAPIView, CreateModelMixin | post | 列表页新增对象功能 |
ListAPIView | GenericAPIView, ListModelMixin | get | 获得列表页内容 |
ListCreateAPIView | GenericAPIView, ListModelMixin, CreateModelMixin | post,get | 完整的列表页功能 |
RetrieveAPIView | GenericAPIView, RetrieveModelMixin | get | 获取单个对象 |
UpdateAPIView | GenericAPIView, UpdateModelMixin | put、 patch | 修改单个对象 |
DestroyAPIView | GenericAPIView, DestroyModelMixin | delete | 删除单个对象 |
RetrieveUpdateDestroyAPIView | GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin | get、 put、 patch、 delete | 完整的详情页查、 改、删 功能 |
2.路由
总路由和子路由配置不变。和五中的配置保持一致
3.视图使用
视图函数如下:这里需要指定queryset和序列化器类就可以了。
优点:
1.继承的类更加简洁明了
2.不用再写get、post、put、delete等所有方法了。
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
from .models import *
from .serializers import *
class test(ListCreateAPIView):
queryset = student.objects.all()
serializer_class = student_serializers
class testDetail(RetrieveUpdateDestroyAPIView):
queryset = student.objects.all()
serializer_class = student_serializers
七、路由Router与视图集ViewSets
concreteAPIView视图类已经非常简练了,已经不用再写操作数据库的逻辑代码。只需要指定数据集合和序列化器类就可以了。
但是目前的状况还是有一点问题:
1.路由要写两条。一条是列表页路由,一条是详情页路由
2.视图函数也是两个,一个是列表页处理函数,一个是详情页处理函数。并且要重复指定queryset和serializer_class
DRF中的router解决了问题1
DRF中的ViewSets解决了问题2
1.配置总路由
编辑urls.py
from django.urls import path,include
urlpatterns = [
path('app1/',include('app1.urls')),
]
2.配置子路由
编辑app1下的urls.py文件
from django.urls import path
from .views import *
from rest_framework.routers import SimpleRouter
urlpatterns = [
]
router = SimpleRouter()
router.register('db',test)
# 查看生成了哪些路由条目
for url in router.urls:
print(f'url = {url}')
urlpatterns += router.urls
在启动项目的时候在日志中可以看到生成了两条路由
# 这个对应列表页路由
url = <URLPattern '^db/$' [name='student-list']>
# 这个对应详情页路由
url = <URLPattern '^db/(?P<pk>[^/.]+)/$' [name='student-detail']>
3.配置视图集
这里的视图类也不在用写两个了,写一个就可以了文章来源:https://www.toymoban.com/news/detail-832984.html
from rest_framework.viewsets import ModelViewSet
from .models import *
from .serializers import *
class test(ModelViewSet):
queryset = student.objects.all()
serializer_class = student_serializers
测试增删改查查文章来源地址https://www.toymoban.com/news/detail-832984.html
到了这里,关于django的DRF(三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!