Django-类视图


为同一接口支持不同的请求类型

request

我们知道当URL文件匹配到用户输入的路径后,会调用对应的view函数,并将request对象作为第一个参数传入该函数。request就是HttpRequest对象的实例,属性包含了关于此次请求的大多数重要信息。

支持不同的请求类型

既然request带有类型,我们就根据不同类型判断,执行对应的操作。修改子应用的views.py文件。

def login(request):
    if request.method == 'GET':
        return HttpResponse('Hello, 这是一个get请求的登录的页面!')
    elif request.method == 'POST':
        return HttpResponse('Hello, 这是一个post请求的登录的页面!')
    else:
        return HttpResponse(f'Hello, 这是一个其他请求的登录的页面!{request.method}')

测试的时候发现,除get外,其他请求方式会报403错误。
在这里插入图片描述
这是因为Django发起其他请求时,会验证CSRF,需要携带CSRF TOKE才行,如果没有,就会报这个异常。我们可以在setting.py文件中关掉CsrfViewMiddleware中间件。
在这里插入图片描述但是这种函数视图不好管理,所有的代码都在一个方法中,不好维护,我们可以使用类视图来优化一下。

类视图

我们将上面那个例子改写成类视图的写法:

class user_login(View):
    def get(self, request):
        return HttpResponse('Hello, 这是一个get请求的登录的页面!')

    def post(self, request):
        return HttpResponse('Hello, 这是一个post请求的登录的页面!')

    def put(self, request):
        return HttpResponse('Hello, 这是一个put请求的登录的页面!')

需要注意的是类视图要继承View。不同的请求方式是与请求方法对应的,如get请求就会自动调用get方法。
看了View的源码,支持的请求方式有:http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
修改完视图后,还需新增一个路由。修改urls.py文件:

urlpatterns = [
    path('user_login/', user_login.as_view()),
]

与函数视图的路由不同的是,第二个参数为函数名.as_view()

总结一下,类视图可读性和复用性更好,不同的请求方式以不同的方法呈现,后面我们就都用类视图了。

我们前面的例子都有一个问题,就是没有一个完整的前端页面,我们现在把前端页面也加上。
在项目根目录新建一个templates文件夹,专门放前端代码。在此文件夹中新建一个login.html。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>项目列表页</title>
    <style>
        .container-fluid {
            margin-top: 100px;
        }
        .table-striped th, .table-striped td {
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="container-fluid">
        <div class="row" style="margin-bottom: 30px">
            <div class="col"></div>
            <div class="col"><h2 class="text-center text-info">项目列表信息</h2></div>
            <div class="col"></div>
        </div>
        <div class="row">
            <div class="col"></div>
            <div class="col">
                <table class="table table-striped">
                  <thead class="thead-dark">
                    <tr>
                      <th scope="col">序号</th>
                      <th scope="col">项目名称</th>
                      <th scope="col">项目负责人</th>
                      <th scope="col">应用名称</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <th scope="row">1</th>
                      <td>一个测试项目</td>
                      <td>Aaron</td>
                      <td>测试项目</td>
                    </tr>
                  </tbody>
                </table>
            </div>
            <div class="col"></div>
        </div>
    </div>
</body>
</html>

写完前端代码后,还需要在setting.py文件中指定前端代码的存放路径。
在这里插入图片描述然后修改子应用的views.py文件,在适当的时候返回这个页面。

class user_login(View):
    def get(self, request):
        return render(request, 'login.html')

再刷新一下页面就看到效果了。
在这里插入图片描述

前后端不分离

前面的例子有一个缺点,就是页面是写死的,但是一般来说,我们前端页面的数据都是从数据库取的,所以还需要在修改一下。
将前端的页面修改一下,把刚才写好的数据删掉,替换成动态的(这个不需要掌握,了解一下即可):

{% for foo in datas %}
 <tr>
    <th scope="row">{{ forloop.counter }}</th>
    <td>{{ foo.project_name }}</td>
    <td>{{ foo.leader }}</td>
    <td>{{ foo.app_name }}</td>
 </tr>
{% endfor %}

修改子应用的views.py文件。

class user_login(View):
    def get(self, request):
        # 假设这是从数据库取的数据
        datas = [
            {
                "project_name": "项目1",
                "leader": "Aaron",
                "app_name": "第一个app"
            },
            {
                "project_name": "项目2",
                "leader": "小伍",
                "app_name": "第二个app"
            },
        ]
        return render(request, 'login.html', context=locals()) # context参数把数据传到html中

此时就可以看到前端页面数据是上面列表中的数据了。
在这里插入图片描述
但是这种方法不好,前后端职责不清,后端还需要去改前端代码,造成项目管理混乱,而且拓展性也差。所以一般我们不使用这种做法。我们采用前后端分离来做。

前后端分离

后端给前端返回json数据

如果需要后端给前端返回数据,那么子应用的views.py文件中,该方法的返回值就需要修改一下:

    def get(self, request, pk):
        # a.使用JsonResponse可以返回json数据
        # b.如果第一个参数为字典,那么无需指定safe关键字参数
        # c.如果第一个参数为嵌套字典的列表,那么必须指定safe=False关键字参数
        # d.可以使用status来指定响应状态码
        return JsonResponse(data=datas, safe=False, status=201)

后端解析前端的数据

query string参数接收

http://127.0.0.1:8000/login/user_login/?name=Aaron&age=18中的?name=Aaron&age=18就是query string查询字符串参数。
通过debug我们不难发现,传入的参数在request对象中。
在这里插入图片描述我们通过request.GET就能获取到前端传来的query string字符串参数,request.GET获取到的是一个QueryDict类型的参数,这是继承了Dict的类型,我们可以使用字典的取值方式来取值。

如果字符串参数中的key重复,会把相同key的值放入列表。例如:?name=Aaron&age=18&name=heihei,我们获取到的就是{‘name’:['Aaron','heihei'],'age','18'},此时再使用字典获取值的方式获取name,获取到的数据就是‘heihei’,我们想要获取到name列表,就要用到QueryDict的getlist方法来获取。request.GET.getlist('name')

请求体参数接收

x-www-form-urlencoded

可以使用request.POST获取x-www-form-urlencoded参数,具体操作方式同上面的query string参数。

json参数

可以使用request.body获取json参数,获取到的是字节类型,我们需要使用decode('utf-8')进行解码,解码后得到一个json的字符串形式,我们在转换成字典就可以取值了。

json_dict = json.loads(request.body.decode('utf-8')) # {‘name’:'Aaron','age','18'}
form-data

form-data和x-www-form-urlencoded的区别是form-data可以传文件参数,form-data的文本参数使用request.POST获取,非文本参数使用request.body获取。

请求头参数

可以使用request.META获取请求头参数,传入的请求头参数为{‘name’:‘Aaron’,‘age’,‘18’},python会把参数名转换为大写,并且加上前缀HTTP_。如果参数名有-,就转换成_。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值