django的DRF(三)

一、基本概念

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()

如下图:

用户
列表页路由 test.as_view
详情页路由 testDetail.as_view
test视图类
testDetail视图类
def get:查询所有资源
def post:添加资源
def delete:删除单个资源
def put:修改单个资源
def get:获取单个资源

五、通用视图类

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组合方式方法功能
CreateAPIViewGenericAPIView, CreateModelMixinpost列表页新增对象功能
ListAPIViewGenericAPIView, ListModelMixinget获得列表页内容
ListCreateAPIViewGenericAPIView, ListModelMixin, CreateModelMixinpost,get完整的列表页功能
RetrieveAPIViewGenericAPIView, RetrieveModelMixinget获取单个对象
UpdateAPIViewGenericAPIView, UpdateModelMixinput、 patch修改单个对象
DestroyAPIViewGenericAPIView, DestroyModelMixindelete删除单个对象
RetrieveUpdateDestroyAPIViewGenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixinget、 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.配置视图集

这里的视图类也不在用写两个了,写一个就可以了

from rest_framework.viewsets import ModelViewSet
from .models import *
from .serializers import *

class test(ModelViewSet):
    queryset = student.objects.all()
    serializer_class = student_serializers

测试增删改查查

  • 30
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值