Django RestFramework学习笔记

文章目录

    • @[toc]
      • 安装
      • 使用细节
        • 修改`settings.py`
        • 在app中创建`serializers.py`文件——序列化文件
        • 在`views.py`中创建类
        • 在`urls.py`中注册路由
      • 请求
        • http请求方式
        • 状态码
        • 使用例子
      • 自定义数据返回结构
      • 解决跨域请求问题
        • 方法1 修改settings配置, 避开csrf验证
        • 方法2 使用csrf_exempt装饰器对特定view进行屏蔽
        • 方法3 重写SessionAuthorization中的enforce_csrf
      • filter筛选
      • 分页
      • 参考

安装

pip install djangorestframework

使用细节

修改settings.py
INSTALLED_APPS中加入’rest_framework’,
在app中创建serializers.py文件——序列化文件
from rest_framework import serializers
from .models import MyModel


class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        # 关联数据表(前面不是变量名)
        model = MyModel
        # 确定需要序列化的字段(返回给用户的具体表中的字段)(前面不是变量名)
        fields = ['id', 'user', 'tel', 'address', 'city' 'province', 'country']
        # fields = "__all__"  # 所有字段

    # 对返回数据做处理, 可无
    def to_representation(self, instance):

        data = super().to_representation(instance)

        try:
            data['country'] = 'China' 
        except Exception as e:
            data['country'] = ''

        return data
views.py中创建类
from rest_framework import mixins,viewsets
from .serializers import MyModelSerializer
from .models import MyModel


class MyModelViews(mixins.ListModelMixin,      # 表示可以在Postman类似的软件中只能查找所有数据 GET
                   mixins.RetrieveModelMixin,  # 表示可以在Postman类似的软件中只能查找单一数据 GET
                   mixins.UpdateModelMixin,    # 表示可以在Postman类似的软件中更新数据 PUT/PATCH
                   mixins.DestroyModelMixin,   # 表示可以在Postman类似的软件中删除数据 DELETE
                   mixins.CreateModelMixin,    # 表示可以在Postman类似的软件中创建数据 POST
                   viewsets.GenericViewSet     # 必须有
                  ): 

    # 查询所有信息
    queryset = MyModel.objects.all()
    # 序列化
    serializer_class = MyModeltSerializer
urls.py中注册路由
from rest_framework.routers import SimpleRouter
from . import views

urlpatterns = [
    # 其他url
]
router = SimpleRouter()
router.register(r'^api/model_test', views.MyModelViews)

urlpatterns += router.urls

请求

http请求方式
GET(SELECT):从服务器取出资源(一项或多项)

POST(CREATE):在服务器新建一个资源

PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)

PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)

DELETE(DELETE):从服务器删除资源
状态码

服务端向用户返回请求api的结果,在结果中包含了status codes 状态码的,可以通过状态码去判断请求api的状态是成功还是失败

200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。

201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。

202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)

204 NO CONTENT - [DELETE]:用户删除数据成功。

400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。

401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。

403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。

404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。

406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。

410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。

422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。

500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
使用例子
增: POST http://127.0.0.1:8000/api/model_test/

删(某条数据): DELETE http://127.0.0.1:8000/api/model_test/1/

改(某条数据): PUT/PATCH http://127.0.0.1:8000/api/model_test/1/

查(返回全部数据): GET http://127.0.0.1:8000/api/model_test/

查(返回单条数据): GET http://127.0.0.1:8000/api/model_test/1/

自定义数据返回结构

1.新建py, 如utils.py

2.继承JSONRenderer类,重构render方法

from rest_framework.renderers import JSONRenderer

class CustomJsonRenderer(JSONRenderer):

    def render(self, data, accepted_media_type=None, renderer_context=None):
        """
        格式
        {
            'code': xxx,
            'msg': 请求成功,
            data: {返回数据}
        }
        """
        if renderer_context:
            if isinstance(data, dict):
                # pop(参数1,参数2) 若参数1不存在,默认取参数2的值
                msg = data.pop('msg', '请求成功')
                code = data.pop('code',0)
            else:
                msg = '请求成功'
                code = 0
            response = renderer_context['response']
            response.status_code = 200
            res = {
                'code': code,
                'msg': msg,
                'data': data
            }
            return super().render(res, accepted_media_type, renderer_context)
        else:
            return super().render(data, accepted_media_type, renderer_context)

3.配置setting.py
添加以下配置

# 配置restful api 返回结果
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'utils.CustomJsonRenderer',
    )
}

其中utils.CustomJsonRenderer是重构的render方法所在的文件路径

解决跨域请求问题

方法1 修改settings配置, 避开csrf验证
  1. pip install django-cors-headersr
  2. 修改django项目中的setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders', # 放在新建的其他项目之前
    'app01',
]
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware', #注意顺序,必须放在这儿
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
#允许所有的请求头
CORS_ALLOW_HEADERS = ('*')

方法1会避开所有csrf验证,安全性较差。

方法2 使用csrf_exempt装饰器对特定view进行屏蔽
  1. views.py中导入装饰器,其中csrf_exempt是不验证csrf,csrf_protect是要验证csrf。
from django.views.decorators.csrf import csrf_exempt,csrf_protect
  1. 方法上直接加装饰器
@csrf_exempt
def testViews(request):
    ...
  1. 类需引入method_decorator,使用@method_decorator(wapper_name, name='post')方式添加
@method_decorator(csrf_exempt, name='post')    #给方法post加装饰器
@method_decorator(csrf_exempt, name='get')
class MyModelViews(mixins.ListModelMixin,...):
    ...

也可直接给View中的dispatch方法加装饰器,这样同样可以实现给自己类下的所有方法加装饰器(自己未定义dispatch方法时)

@method_decorator(csrf_exempt, name='dispatch')
class MyModelViews(mixins.ListModelMixin,...):
    ...
  1. 在response中添加响应
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, PUT, PATCH, DELETE, OPTIONS"  # 可选部分
response["Access-Control-Allow-Headers"] = "*"

可在view中的response直接添加,也可在重构的render方法中添加

...
response = renderer_context['response']
response.status_code = 200
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, PUT, PATCH, DELETE, OPTIONS"
response["Access-Control-Allow-Headers"] = "*"
res = {
       'code': code,
       'msg': msg,
       'data': data
      }
...
方法3 重写SessionAuthorization中的enforce_csrf
  1. Problem

用户登陆功能,使用的就是SessionAuthorization和TokenAuthorization,然后在SessionAuthorization中调用了self.enforce_csrf(request)而这个调用的又是上面的CSRFCheck,这个类是重载了django里面的csrf middleware,而且没发现有地方可以关掉这个功能,即使在django里面去掉这个middleware,但是这个还是会调用的。

  1. Solve
  • 在views中重写SessionAuthentication的enforce_csrf方法。
class CsrfExemptSessionAuthentication(SessionAuthentication):
    """
    去除 CSRF 检查
    """
    def enforce_csrf(self, request):
        return # To not perform the csrf check previously happening
  • 在view中添加authentication_classes以使用重写的认证方法。

在 APIView 中,如果提供了 authentication_classes ,则会使用提供的认证后端来进行认证。如果没有提供,则会使用默认的认证后端。

class XXView(mixins.ListModelMixin,...,
             viewsets.GenericViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
    
    ...
    
    # 去除 CSRF 检查
    authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
    
    ...
    

filter筛选

  1. 安装pip install django-filter
  2. 在配置文件settings.pyINSTALLED_APPS添加应用django_filters
INSTALLED_APPS = [
  ...
  'rest_framework',
  'django_filters',
  ...
]
  1. views.py中引入包
from rest_framework import filters
from django_filters import rest_framework
  1. view中添加相应的过滤条件
from rest_framework import mixins,viewsets
from .serializers import MyModelSerializer
from .models import MyModel

from rest_framework import filters
from django_filters import rest_framework

class MyModelViews(mixins.ListModelMixin,      # 表示可以在Postman类似的软件中只能查找所有数据 GET
                   mixins.RetrieveModelMixin,  # 表示可以在Postman类似的软件中只能查找单一数据 GET
                   mixins.UpdateModelMixin,    # 表示可以在Postman类似的软件中更新数据 PUT/PATCH
                   mixins.DestroyModelMixin,   # 表示可以在Postman类似的软件中删除数据 DELETE
                   mixins.CreateModelMixin,    # 表示可以在Postman类似的软件中创建数据 POST
                   viewsets.GenericViewSet     # 必须有
                  ): 

    queryset = MyModel.objects.all()
    serializer_class = MyModeltSerializer
    filter_backends = (rest_framework.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter, )
    filter_class = ServerFilter
    search_fields = ('user', 'city', 'province', 'country')
    ordering_fields = ('id', user', 'city', 'province', 'country')
    ordering = ('-id', )
  1. 编写ServerFilter
import django_filters
from .models import *


class ServerFilter(django_filters.rest_framework.FilterSet):
  
 
  class Meta:
    model = MyModel
    fields = ['id', user', 'city', 'province', 'country']
  1. 过滤设定了过滤的配置类为ServerFilter,也就是说可以通过’id’, user’, ‘city’, ‘province’, 'country’对物理服务器的信息进行过滤,得到相应的序列化列表。
# 获取城市为guangzhou的数据
http://127.0.0.1:8000/api/model_test/?city=guangzhou
  1. 搜索需要指定search关键字需要查询的信息
http://127.0.0.1:8000/api/model_test/?search=test

在search_fields中可以指定多种查找方式:

  • ‘^name’ 以name开头
  • ‘=name’ 精确匹配
  • ‘@’ 全局检索(只有mysql数据源支持)
  • ‘$’ 正则匹配

search_fields = ('^city', '=province', 'country', )

  1. 排序:在ordering字段指定了默认排序方式,-为倒序
ordering = ('-id', )

如果要自定义排序字段,需要指定ordering字段的内容:
http://127.0.0.1:8000/api/model_test/?ordering=user

分页

修改settings.py

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}

查找多个数据库记录时使用的语法,客户端包括“limit”和“offset”查询参数,limit指示要返回的最大项目数,并且相当于其他样式中的page_size,offset表示查询起始位置。

# example
http://127.0.0.1:8000/api/model_test/?limit=10
http://127.0.0.1:8000/api/model_test/?limit=10&offset=20

参考

  1. Django用restful实现数据的增删改查
  2. Django的restful用法(自带的增删改查)
  3. Django解决跨域请求的问题
  4. django rest framework 数据的查找、过滤、排序的示例
  5. django-rest-framework(实战篇)——过滤、搜索、排序、分页
  6. Django REST 系列教程(三)(下)
  7. 去掉django rest framework强制的csrf检查

你可能感兴趣的:(Django,Python,Django,RestFramework)