JsonResponse

向前端返回一个json格式字符串的两种方式

方式一:

import json

def json_data(request):
    user_dict = {'name': 'kevin', 'age': 22, 'hobby': '足球'}
    dict_json = json.dumps(user_dict, ensure_ascii=False)
    return HttpResponse(dict_json)

方式二:

def json_data(request):
    user_dict = {'name': 'kevin', 'age': 22, 'hobby': '足球'}
    return JsonResponse(user_dict, safe=False, json_dumps_params={'ensure_ascii': False})
  • 默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象
  • 只所以使用JsonResponse是因为djangojson序列化的数据类型的范围做了扩充

form表单上传文件

演示

urls.py

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^register/$', views.register),
]

view.py

def register(request):
    if request.method == 'POST':
        name = request.POST.get('name')
        header_img = request.FILES.get('header_img')
        with open(header_img.name, 'wb') as f:
            for line in header_img:
                f.write(line)
        return HttpResponse('注册成功')
    return render(request, 'register.html')

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <h1 class="text-center">注册</h1>
        <div class="col-lg-8 col-md-offset-2">
            <form action="" method="post" enctype="multipart/form-data">
                {% csrf_token %}
                <p>昵称:
                    <input type="text" class="form-control" name="name">
                </p>
                <p>头像:
                    <input type="file" name="header_img" multiple>
                </p>
                <input type="submit" class="btn btn-success btn-block" value="注册">
            </form>
        </div>
    </div>
</div>

</body>
</html>

总结

form表单上传的数据中如果含有文件 那么需要做以下几件事

  • method必须是post
  • enctype必须修改为multipart/form-data,默认是application/x-www-form-urlencoded
  • 后端需要使用request.FILES获取( django会根据数据类型的不同自动帮你封装到不同的方法中)

request其他方法

  • request.method:获取请求方法
  • request.GET or request.POST:获取GET or POST请求参数,字典形式。
  • request.POST.get('name',default=None):获取POST请求参数
  • request.GET.getlist('name',default=None): 获取GET参数列表
  • request.META:包含当前HTTP请求的Headers头部信息, 字典形式。键值KEY都是大写。比如request.META['REMOTE_ADDR']可获取用户远程IP地址。
  • request.user:获取当前访问用户的所有信息。
  • request.path:获取当前访问路径
  • request.FILES:获取上传文件的数据
  • request.body:获取的是二进制数据(request.POSTrequest.GETrequest.FILES这些获取数据的方法其实都从body中获取数据并解析存放的)
  • request.path_info:获取当前访问路径
  • request.get_full_path():获取路径并且还可以获取到路径后面携带的参数

FBV与CBV

django的视图层由两种形式构成:FBVCBV

FBV

FBV基于函数的视图(Function base view)

urls.py

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^fbv/$',views.fbv),
]

view.py

from django.shortcuts import render, HttpResponse, redirect

def fbv(request):
    return HttpResponse('from FBV')

CBV

CBV基于类的视图(Class base view)

urls.py

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^cbv/$', views.MyIndexView.as_view()),
]

view.py

from django import views


class MyIndexView(views.View):
    def get(self, request):
        return HttpResponse('from CBV get view')

    def post(self, request):
        return HttpResponse('from CBV post view')

运行后的结果是:

​ 如果请求方式是GET则会自动执行类里面的get方法;如果请求方式是POST 则会自动执行类里面的post方法

CBV源码解析

​ 通过路由匹配做为切入点,类名.as_view(),(函数名加括号执行优先级最高)对象查找的顺序是先从自身,再从产生对象的类,再从父类。先从自己写的MyIndexView类中查找as_view,没有再去MyIndexView类中的父类查找,查看View类中找了as_view可以看到Djangoas_vie方法加了@classonlymethod装饰器,作用是只允许类对象调用这个方法(绑定给类的方法)。

    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs) 
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view

可以看到最后返回的是一个return viewview是一个闭包函数(定义在as_view函数内部的函数,并且内部还用到了外部名称空间的名字)。相当于url(r'^cbv/$', views.MyIndexView.as_view()),变成了url(r'^cbv/$', views.view()),可以推导出CBVFBV在路由匹配本质是一样的。

当执行view函数,self = cls(**initkwargs) 等同于self = MyIndexView(**initkwargs)意思是产生一个类的对象,最后返回的是一个self.dispatch(request, *args, **kwargs),继续查看dispath函数源码

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

上述也就是CBV核心代码,可以看到返回的是 handlerhandler用了反射中getattr(通过字符串获取对应的变量名或者函数名)

handler = getattr(自己写的类产生的对象, 'get', 当找不到get属性或方法就会用第三个参数)

简单说就是handler = 自己写的类里面的get方法

Last modification:May 16, 2022
如果觉得我的文章对你有用,请随意赞赏