• Django04


    零:Django视图层

    Django视图层相关的知识都是在APP下的views.py中所应用的,视图层的主要功能就是如何处理由路由层解析过来的request请求,主要包含以下几块内容

    1.如何处理request请求对象

    2.如何返回一个HTML文档或其他内容给前端页面

    3.如何对接上数据库实时获取数据

    一:请求对象

    这里的request是django封装的对象,它的类是WSGIRequest,它里面包含了所有http请求的东西

    print(request)          # <WSGIRequest: GET '/upload/'>
    print(type(request))    # <class 'django.core.handlers.wsgi.WSGIRequest'>
    

    WSGIRequest继承了http的HttpRequest

    image-20201012073209270

    HttpRequest中,内置了许多方法

    请求对象的方法

    request.method - 返回请求的方法
    print(request.method)		# GET、POST等
    
    request.GET - QueryDict对象,保存了用户提交过来的数据(不包含文件)
    http://127.0.0.1:8000/index/?name=Darker&age=18 	# 手动在地址栏填入的数据
    
    print(request.GET)		# <QueryDict: {'name': ['Darker'], 'age': ['18']}>
    
    request.POST - QueryDict对象,保存了用户提交过来的数据(不包含文件)
    http://127.0.0.1:8000/index/?name=Ben&gender=male 	# 手动在地址栏填入的数据
    
    print(request.POST)		# <QueryDict: {'name': ['Ben'], 'gender': ['male']}>
    
    request.is_ajax() - 判断是不是ajax请求
    print(request.is_ajax())		# True / False
    
    request.path - 返回当前访问的路径
    http://127.0.0.1:8000/index/?name=Darker&age=18
    
    print(request.path)		# /index/
    
    request.get_full_path() - 返回当前访问的完整路径
    http://127.0.0.1:8000/index/?name=Darker&age=18
    
    print(request.get_full_path())		# /index/?name=Darker&age=18
    
    request.encoding - 客户端向服务端传递时,使用的编码方法
    print(request.encoding)		# urlencoded / form-data / json
    
    request.META - *重要 | 包括了很多信息

    request.META中的信息

    print(request.META['SERVER_PORT'])      # 服务的端口  8080
    print(request.META['SERVER_PROTOCOL'])  # 服务的HTTP协议  HTTP/1.1
    print(request.META['REMOTE_ADDR'])      # 访问的设备IP   127.0.0.1
    print(request.META['CONTENT_TYPE'])     # 客户端向服务端发送的编码方式    text/plain
    print(request.META['HTTP_HOST'])        # 主机IP  127.0.0.1:8080
    print(request.META['HTTP_USER_AGENT'])  # 访问设备的浏览器类型    Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X MetaSr 1.0
    print(request.META['HTTP_REFERER'])     # 访问的前一个URL http://127.0.0.1:8080/index/
    
    request.FILES - 用户上传的文件

    二:响应对象

    HttpResponse - 接收一个字符串并返回

    from django.shortcuts import HttpResponse
    
    def return_HttpResponse(request):
        return HttpResponse("Hello World")
    

    render

    render()有多个参数,其中第一个参数为返回request请求对象,其他参数则用于返回HTML文档及其局部命名空间内变量用作模板渲染。

    参数 内容
    request 用于生成响应的请求对象
    template_name 要使用的模板的完整名称,可选的参数
    context 添加到模板上下文的一个字典
    默认是一个空字典
    如果字典中的某个值是可调用的,视图将在渲染模板之前调用它
    局部命名空间变量(字典形式从换入),或locals()函数
    from django.shortcuts import render
    
    def return_render(request):
    
        user_msg = {"name":"Darker","age":18,"gender":"male"}
    
        return render(request,"login.html",{"user_msg":user_msg}) 
    
        # 参数3:{"user_msg":user_msg}  只传递user_msg到HTML文档
        # 参数3:locals() 将当前函数的命名空间(return_render)下的所有变量传递到HTML文档
    

    redirect - 接收一个url并返回,状态码为302,即重定向

    from django.shortcuts import redirect
    
    def return_redirect(request):
        return redirect("http://www.xuexianqi.top") # 跳转到www.xuexianqi.top | 这里的参数可以是一个路由,也可以是一个完整的URL
    

    JsonResponse

    JsonresponseDjango中自带的一个基于json模块的封装,可以直接返回json类型的数据至模板层的前端页面。

    1.只支持字典,如果想传递其他数据类型需要将safe设置为False

    2.如果想让转换后的json格式字符串中存在中文,请设置参数json_dumps_params={"ensure_ascii":False},即关闭自动转码

    from django.http import JsonResponse
    
    def f1(request):
        data = {"name":"Darker","age":18}
        return JsonResponse(data,json_dumps_params={"ensure_ascii":False})  # 只支持字典,关闭自动转码
    

    本质

    redirectrenderJsonResponse的本质,都是HttpResponse

    # 这里以render为例,用HttpResponse来实现
    
    def f1(request):
        data = {"name":"Darker","age":18}
    
        from django.template import Template,Context
        
        res = Template("<h1>{{user}}<h1>")  # 模板,将HTML代码渲染成模板
        con = Context({"user":{"name":"Darker"}}) # 替换的内容封装成Context对象
        ret = res.render(con) # 执行替换
        
        return HttpResponse(ret)
    

    三:CBV与FBV

    FBV - Function Based View:基于函数的视图

    FBV是在视图层里通过函数的方式进行逻辑处理。

    具体用法:

    # urls.py
    
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url('^index/', views.index)  # 这里的index后面不能加括号
    ]
    
    # views.py
    
    from django.shortcuts import HttpResponse
    
    def index(request):
        if request.method == 'POST':
            return HttpResponse("这是POST请求")
        else:
            return HttpResponse("这是GET请求")
    

    CBV - Class Based View:基于类的视图

    CBV是在视图层里通过类的方式进行逻辑处理。

    具体用法:

    # urls.py
    
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url('^index/', views.Index.as_view())  # 这里的as_view后面需要加上括号
    ]
    
    # views.py
    
    from django.shortcuts import HttpResponse
    from django.views import View # 导入View
    
    class Index(View): # 必须继承View
     
        def get(self,request):  # 当get请求来,执行该方法
            return HttpResponse("这是GET请求")
    
        def post(self,request): # 当post请求来,执行该方法
            return HttpResponse("这是POST请求")
    

    CBV源码分析

    @classonlymethod  # django封装的类方法,只能用于装饰class(类)
    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):  # 这是1个闭包函数,此时不会运行
            self = cls(**initkwargs)  # self=Index,这里的Index就是自己在views.py中定义的类
            if hasattr(self, 'get') and not hasattr(self, 'head'):  # 如果有Index类有get方法并且没有head方法
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)  # 将request对象传进去, 执行dispatch,并返回
    
        view.view_class = cls  # view.view_class = Index
        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=())  # 这里的cls.dispatch就是Index.dispatch,但是并没有加括号去执行
        return view  # 返回view,接下来才执行。
    

    1.请求来了,匹配成功之后,会在路由中进行匹配

    url('^index/', views.Index.as_view())
    
    # 这里的 views.Index.as_view() 是一个函数的内存地址,或者说:一定是一个可调用对象
    

    2.此时,会传一个request对象进去

    url('^index/', views.Index.as_view()(request))
    

    3.本质就是内层函数的闭包函数view()

    url('^index/', views.Index.view(request))
    

    4.view()中,执行了self.dispatch()

    url('^index/', views.Index.dispatch(request))
    
        def dispatch(self, request, *args, **kwargs):
    		# 说白了就是判断请求方式,是不是在这个 self.http_method_names 里头,如果在handler就是一个请求模式的方法,比如get或者post
            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) # 执行并返回了
    
    

    5.最后,if request.method.lower() in self.http_method_names

    def dispatch(self, request, *args, **kwargs):
        # 判断请求方式,是不是在这个 self.http_method_names 里,如果在handler就是一个请求模式的方法,比如get或者post
        if request.method.lower() in self.http_method_names:    # 这里 self.http_method_names 的 self 寻找顺序需要理清楚,这里的self,是Index
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # 执行并返回了
    

    这里的self就是Index

    也就是说,我们可以在Index中,自己定义一个http_method_names列表,来限制允许的请求

    class Index(View):
    	http_method_names = ['post', 'get']	# 表示只允许post和get请求
    

    如果没有自定义的这个列表,那么就会去找Viewhttp_method_names列表

    class View(object):
        """
        Intentionally simple parent class for all views. Only implements
        dispatch-by-method and simple sanity checking.
        """
    
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    

    6.总结

    as_view()会执行View.dispatch()这个方法,这个方法内部其实就会执行GET或者POST方法。

    FBV装饰器

    FBV添加装饰器,一般我们会单独将request提取出来。

    from django.shortcuts import HttpResponse
    
    def wrapper(func):
    	def inner(request,*args,**kwargs):
    		return func(request,*args,**kwargs):
    	return inner
    
    @wrapper
    def other(request):
    	return HttpResponse("other...")
    

    CBV装饰器

    CBV添加装饰器的方式有三种。针对不同的应用场景可以使用不同的装饰器添加方法,但是有一点是相同的。

    都需要先导入下面这个模块:

    from django.utils.decorators import method_decorator
    

    方式1 - 为单独的某个功能添加装饰器

    from django.shortcuts import HttpResponse
    from django.views import View
    from django.utils.decorators import method_decorator
    
    def wrapp(func):
    	def inner(request,*args,**kwargs):
    		return func(request,*args,**kwargs):
    	return inner
    
    class Other(View):
        @method_decorator(wrapp)
        def get(self, request):
            return HttpResponse("get方法...")
            
         @method_decorator(wrapp)
        def post(self,request):
            return HttpResponse("post方法...")
    

    方式2 - 为CBV类添加装饰器,可指定该装饰器作用与类下的那些方法(可添加多个)

    from django.shortcuts import HttpResponse
    from django.views import View
    from django.utils.decorators import method_decorator
    
    def wrapp(func):
    	def inner(request,*args,**kwargs):
    		return func(request,*args,**kwargs):
    	return inner
    
    
    @method_decorator(wrapp,name="get")
    @method_decorator(wrapp,name="post")
    class Other(View):
        def get(self,request):
            return HttpResponse("get方法...")
    
        def post(self,request):
            return HttpResponse("post方法...")
    

    方式3 - 为dispatch方法添加装饰器,该装饰器会作用于所有的方法。(因为入口方法不是post,就是get

    from django.shortcuts import HttpResponse
    from django.views import View
    from django.utils.decorators import method_decorator
    
    def wrapp(func):
    	def inner(request,*args,**kwargs):
    		return func(request,*args,**kwargs):
    	return inner
    
    
    class Other(View):
    	@method_decorator(wrapp)
        def dispatch(self, request, *args, **kwargs):
            return super(Other,self).dispatch(request, *args, **kwargs)
            
        def get(self,request):
            return HttpResponse("get方法...")
    
        def post(self,request):
            return HttpResponse("post方法...")
    

    CBV实现图片上传

    要求:

    1.在浏览器选择要上传的文件,点击按钮上传到指定文件夹

    2.文件类型只能是图片类型

    3.上传的图片需要在浏览器里展示出来

    1.在项目路径下创建MEDIA文件夹
    2.在MEDIA文件夹下创建upload_img文件夹
    3.在settings.py中配置MEDIA的路径
    4.在views.py中编写上传类
    5.在templates文件夹中编写upload.html模板
    6.在urls.py中配置路由
    
    # views.py
    class Upload(View):
        def get(self, request):
            img_list = []
            from django.conf import settings
            for media_path in [settings.MEDIA_ROOT, ]:
                img_list.append(os.listdir(os.path.join(media_path, 'upload_img')))
            return render(request, 'upload.html', {'img_list': img_list})
    
        def post(self, request):
            file = request.FILES.get('myfile')
            if file:
                if str(file.name).endswith('jpg' or 'jpeg' or 'bmp' or 'gif' or 'png'):
                    from django001 import settings
                    path = os.path.join(settings.MEDIA_ROOT, "upload_img", file.name)
                    with open(path, 'wb') as f:
                        for line in file.chunks():
                            f.write(line)
                    return HttpResponse('图片上传成功')
                else:
                    return HttpResponse('文件类型错误')
            else:
                return HttpResponse('请选择文件')
    
    # upload.html
    
    <div class="row">
            <div class="col-md-3">
                <div class="panel panel-default">
                    <div class="panel-heading">图片上传</div>
                    <div class="panel-body">
                        <div class="col-md-4">
                            <form action="" method="post" enctype="multipart/form-data">
                                <br><br>
                                <input type="file" name="myfile" accept="image/*"><br>
                                <button type="submit" class="btn btn-default btn-block">上传图片</button>
                                <br><br>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
    
            <div class="col-md-9">
                <div class="panel panel-default">
                    <div class="panel-heading">图片列表</div>
                    <div class="panel-body x-img">
                        {% for img in img_list %}
                            {% for img1 in img %}
                                <img src="/media/upload_img/{{ img1 }}">
                            {% endfor %}
                        {% empty %}
                            <h2 class="text-center">暂无照片</h2>
                        {% endfor %}
                    </div>
                </div>
            </div>
        </div>
    
    # settings.py
    
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, "media").replace("\", "/")
    
    # urls.py
    
    urlpatterns = [
    	url(r'^upload/', views.Upload.as_view()),
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    
  • 相关阅读:
    Java基础知识强化之集合框架笔记20:数据结构之 栈 和 队列
    Java基础知识强化之集合框架笔记19:List集合迭代器使用之 并发修改异常的产生原因 以及 解决方案
    模块已加载,但对dllregisterServer的调用失败
    sql回滚
    BAT 批处理脚本 教程
    shell脚本小技巧
    shell if
    REDHAT4.8安装yum
    Linux中文显示乱码解决
    Nginx配置文件详细说明
  • 原文地址:https://www.cnblogs.com/xuexianqi/p/13844870.html
Copyright © 2020-2023  润新知