Django实现请求方法和必传参数校验

Posted 在奋斗的大道

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django实现请求方法和必传参数校验相关的知识,希望对你有一定的参考价值。

业务背景:

在写views控制层的时候,需要做很多校验,判断请求类型,判断是否有必填项没传,而不同的请求类型,在代码中获取入参的方式也是不同的。

例如:

get请求 :/selectPage/?page=1&pageSize=1这种,使用 request.GET ,可以得到一个QueryDict类型的对象,具备dict同款的get方法,可以通过request.GET.get('a')的方法获取参数

post from 表单请求:/selectPage/?page=1&pageSize=1这种也可以解析,使用request.POST

post请求:对于包裹在body下的json格式入参数,就需要使用request.body来获取,request.body返回的是一个bytes类型,实际要使用还需要例如json.loads进行转换。在这里又需要判断json.body是否有值,需要判断json.loads执行是否无异常,因为本身json化就严格,经常不符合格式要求而报错

请求方法和必传参数校验器核心代码(check.py)

from functools import wraps
import json
from django.http import HttpResponse


def request_verify(request_method: str, need_params=None):
    """
        在views方法上加装饰器 例如:@request_verify('get', ['id'])
        :param request_method:
        :param need_params:
        :return:
    """

    def decorator(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            method = str(request.method).lower()
            # 先判断类型,类型不符合,直接return
            if request_method and not method == request_method.lower():
                response = "method {0} not allowed for: {1}".format(request.method, request.path)
                return response_failure(response)

            request.params = {}
            # 暂时不用get请求传参,get的情况可以先忽略
            if method == 'get':
                if not request.GET:
                    if need_params:
                        response = "缺少参数"
                        return response_failure(response)
                else:
                    params = {}
                    request_params = request.GET
                    for item in request_params:
                        params.update({item: request_params.get(item)})
                    # get 必填参数校验
                    if need_params:
                        for need_param_name in need_params:
                            if not params.get(need_param_name):
                                response = "参数 {0} 不能为空".format(need_param_name)
                                return response_failure(response)
                    request.params = params
            else:  # method == post
                if not request.body or request.body == {}:  # 参数为空的情况下
                    if need_params:  # 验证必传
                        response = "缺失参数"
                        return response_failure(response)
                else:  # 非空的时候,尝试去获取参数
                    try:
                        real_request_params = json.loads(request.body)  # 这边要try一下,如果前端传参不是json,json.loads会异常
                    except Exception as e:
                        response = "参数格式不合法"
                        return response_failure(response)
                    # 取出来以后再去判断下必填项是否每一项都有值
                    if need_params:
                        for need_param_name in need_params:
                            if not real_request_params.get(need_param_name):
                                # 如果必传参数取出来是'' (PS: 没传和传了''通过get取出来都是''),就抛出
                                response = "参数 {0} 不能为空".format(need_param_name)
                                return response_failure(response)
                    # 一直到这里都无异常那么就可以把参数塞进request对象了,避免view里还要再去json.loads
                    request.params = real_request_params
            return func(request, *args, **kwargs)

        return inner

    return decorator


# 校验结果封装
def response_failure(message):
    return HttpResponse(json.dumps({
        'code': 4000,
        'message': message
    }, ensure_ascii=False), 'application/json')

用法

限制请求类型:post 和get 无大小写区分

import json
from userSystem.models import Book
from django.http import HttpResponse
from django.core import serializers
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from userSystem.check import request_verify


# Create your views here.
@request_verify('get')
def select(request):
    books = Book.objects.all()
    for i in range(len(books)):
        print("主键:%s   值:%s" % (i + 1, books[i]))

    return response_success(message='后台响应成功', data_list=serializers.serialize("json", books))


@request_verify('post')
def selectAll(request):
    books = Book.objects.all()
    for i in range(len(books)):
        print("主键:%s   值:%s" % (i + 1, books[i]))
    return response_success(message='后台响应成功', data_list=serializers.serialize("json", books))

限制请求类型 + 必传参数

import json
from userSystem.models import Book
from django.http import HttpResponse
from django.core import serializers
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from userSystem.check import request_verify


@request_verify('get', ['page', 'pageSize'])
def selectPage(request):
    # 当前页码
    page = request.GET.get('page')
    # 当前分页大小
    page_size = request.GET.get('pageSize')
    book_list = Book.objects.all()
    # django 分页实体对象
    paginator = Paginator(book_list, page_size)
    # 查询总记录数
    total = paginator.count
    try:
        # 执行分页查询
        books = paginator.page(page)
    except PageNotAnInteger:
        # 执行分页查询,默认指定页码
        books = paginator.page(1)
    except EmptyPage:
        # 执行分页查询,默认指定页码
        books = paginator.page(paginator.num_pages)
    return response_page_success(message='后台响应成功', data_list=serializers.serialize("json", books), total=total, page=page, pageSize=page_size)


@request_verify('post', ['page', 'pageSize'])
def selectPageAll(request):
    json_str = request.body
    json_str = json_str.decode()  # python3.6及以上不用这一句代码
    dict_data = json.loads(json_str)  # loads把str转换为dict,dumps把dict转换为str

    # 当前页码
    page = dict_data.get('page')
    # 当前分页大小
    page_size = dict_data.get('pageSize')
    book_list = Book.objects.all()
    # django 分页实体对象
    paginator = Paginator(book_list, page_size)
    # 查询总记录数
    total = paginator.count
    try:
        # 执行分页查询
        books = paginator.page(page)
    except PageNotAnInteger:
        # 执行分页查询,默认指定页码
        books = paginator.page(1)
    except EmptyPage:
        # 执行分页查询,默认指定页码
        books = paginator.page(paginator.num_pages)
    return response_page_success(message='后台响应成功', data_list=serializers.serialize("json", books), total=total, page=page, pageSize=page_size)


def response_success(message, data=None, data_list=[]):
    return HttpResponse(json.dumps({
        'code': 200,#code由前后端配合指定
        'message': message,#提示信息
        'data': data,#返回单个对象
        'dataList': data_list#返回对象数组
    }, ensure_ascii=False), 'application/json')


def response_page_success(message, data=None, data_list=[], total=None, page=None, pageSize=None):
    return HttpResponse(json.dumps({
        'code': 200,#code由前后端配合指定
        'message': message,#提示信息
        'data': data,#返回单个对象
        'dataList': data_list,#返回对象数组
        'total':total,#记录总数
        'page':page,#当前页面
        'pageSize':pageSize#当前页面分页大小
    }, ensure_ascii=False), 'application/json')

效果演示:

 

 

 

以上是关于Django实现请求方法和必传参数校验的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot实现数据格式校验

elementui el-upload图片文件上传必传校验

Json协议参数校验在58APP上的设计与应用

Struts2请求参数校验

swagger界面非必传参数的设置

SpringBoot分组校验及自定义校验注解