• Django的日常-视图层


    Django的日常-3

    JsonResponse

    在之前我们就知道,不同语言或者说系统之间,Json格式的数据是通用性最好的,所以我们通常会选择用json格式来从后端向前端传输数据,在Django里面,我们不需要像之前那样导入json模块然后用json.dumps和json.loads来打包和解析json数据,因为我们有一个专门的函数来做json数据的转换,就叫做JsonResponse.

    # 首先我们还是需要导入这个函数
    from django.http import JsonResponse
    # 下面的内容我们需要写在一个函数里面,方便调用
    def index(request):
    	user = {'username':'nick哈哈哈','pwd':'123'}
        return JsonResponse(user,json_dumps_params={'ensure_ascii':False})
        l = [1, 2, 3, 4, 5, 5, 6]
        return JsonResponse(l, safe=False)
    '''
    在使用JsonResponse模块的时候,要注意的几点是:
    	1. JsonResponse默认只支持序列化字典 如果你想序列化其他类型(json能够支持的类型) 你需要将safe参数由默认的True改成False,比如 JsonResponse(l, safe=False)
    	2. 在用JsonResponse序列化的时候,如果内容里面有中文,会自动被解析成二进制码,所以如果我们想要保留中文的话,需要在给JsonResponse传值的时候加入json_dumps_params={'ensure_ascii':False},即不自动解析,这样就能保留原始数据里面的中文,例如JsonResponse(user,json_dumps_params={'ensure_ascii':False})
    '''
    

    form表单上传文件

    我们知道form表单是在前端,也就是html文件里面写的一种格式,可以用来给后端传一些数据,或者上传文件,下面举例form的写法

    # up.html文件里面
    <form action="" method="post" enctype="multipart/form-data">
        <input type="text" name="username">
        <input type="file" name="myfile">
        <input type="submit">
    '''
    这里要注意两点:
    	1. form表单在向后端传输数据的时候,method方法必须是post
    	2. enctype参数必须设置为"multipart/form-data"
    '''
        
        
    # views.py后端
    def up(request):
        if request.method == 'POST':
            print(request.POST)		# 可以取到请求的内容
            print(request.FILES)	
            # 获取文件对象
            file_obj = request.FILES.get('myfile')	# 这里的别名是前端的html文件里定义的别名
            print(file_obj.name)  # 获取文件名
            with open(file_obj.name, 'wb') as f:
                for chunk in file_obj.chunks(): 
                    f.write(chunk)
        return render(request, 'up.html')
    

    CBV的源码分析

    首先,我们要知道CBV的全程为Class Based View,也就是基于类的视图,下面我们通过一个实例来看一下这个东西的作用

    #urls.py    
    urlpatterns = [
        url(r'^reg/',views.MyReg.as_view()),
        #其实上面这句url相当于 url(r'^reg/',views.MyReg.get()),或者 url(r'^reg/',views.MyReg.post()),
    ]
    
    #views.py
    class MyReg(View):
        def get(self, request):
            return render(request, 'reg.html')
    
        def post(self,request):
            return HttpResponse("我是MyReg类中post方法")
    
    #reg.html
    <body>
    <form action="" method="post">
    
        <input type="submit">
    </form>
    </body>
    

    我们在写完以上代码并执行起来以后,输入网址http://127.0.0.1:8000/reg/,可以看到有个提交按钮,按下之后我们可以看到"我是MyReg类中post方法"这句话,那么问题就来了,这个逻辑是怎样的,我们定义的MyReg类是怎么判定你发来的是get还是post请求的,下面我们详细分析一波.

    我们先来看路由层里面,url里所使用的的as_view的部分源码如何:

    #base.py  class View/as_view源码
    class View(object):
        def as_view(cls, **initkwargs):
                def view(request, *args, **kwargs):
                    self = cls(**initkwargs)  # cls就是我们自己的写的MyReg类
                    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)
                # 这里我们看到,最终返回的是self调用dispatch方法,所以我们再找到dispatch的源码来看
                return view
            
    # dispatch源码
        def dispatch(self, request, *args, **kwargs):
                if request.method.lower() in self.http_method_names:  # 判断当前请求方式在不在默认的八个请求方式中,其实我们最常用的就是post和get请求
                    '''
                    八种请求方式为:GET,HEAD,POST,PUT,DELETE,CONNECT,OPTIONS,TRACE
                    '''
                    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                    # handler = getattr(自己写的类产生的对象,'小写的请求方法(getpost)','获取不到对应的方法就报错')
                    # handler就是我们自己定义的跟请求方法相对应的方法的函数内存地址
                    # 我们用反射就是从类对象来反射出来并获取其生成时候的方法,最后返回调用该方法
                else:
                    handler = self.http_method_not_allowed
                return handler(request, *args, **kwargs)  # 在调用获取到的方法
    

    视图层

    模板传值

    模板传值,其实就是把存在于后端的变量值传到前端并通过模板的形式展示出来,模板语法,最常用的符号有两种,即{{}},{% %},其中{{}}里面写入变量相关的内容,{% %}里面写入逻辑相关的内容.

    实例如下:

    #views.py 后端
    
    from datetime import datetime
    from django.utils.safestring import mark_safe
    def login(request):
        n = 123
        f = 12.12
        s = '你妹的 真难'
        l = [1, 2, 3, 4, 5, 6]
        d = {'username': 'jason', 'password': [123, 222, 444]}
        t = (1, 2, 3, 4, 5)
        se = {1, 2, 3, 4}
        b = True
        ctime = datetime.now()
        file_size = 342384234234
        w = '奥术 大师件 大事肯德 基按 实际对 拉 螺栓空当接 龙'
        w1 = 'asdash ashd jkh sadas asdjjs had sjklad j a kjkjdsklas dkjsakldj dlsjakld '
        w2 = 'he llow ord wqe asdsad sadsadsa dsadasds adasds adsadsadsada sdsad'
    
        def func():
            return '你好~'
    
    
        obj = MyClass()
    
        sss = "<h1>一脸懵逼</h1>"
        sss1 = "<script>alert(123)</script>"
        sss2 = "<a href='http://www.baidu.com'>好好学习</a>"
        # mark_safe,转义,即我们会认定这个语句安全,然后让其转义之后再发送给前端,让前端可以直接显示出其特定格式
        res = mark_safe(sss2)
    
        xo = '123213213'
        xo1 = 222
    
        yyy = {'user_list': [1, '22', {'username': ['jason', 'egon']}]}
        return render(request, 'login.html', locals())
    
    
    
    
    #login.html 前端
    <body>
    <p>{{ n }}</p>
    <p>{{ f }}</p>
    <p>{{ s }}</p>
    <p>{{ l }}</p>
    <p>{{ d }}</p>
    <p>{{ se }}</p>
    <p>{{ t }}</p>
    <p>{{ b }}</p>
    {#以上数值类型都可以直接传值并显示出来#}
        
        
    {#如果传递给前端一个函数名,会直接加括号调用,将函数的返回值展示到前端,尤其需要注意的是!!!!!django的模板语法,不支持给函数传参,不支持传参,不支持传参,不支持传参#}
    <p>{{ func }}</p>
    
    
    {#方法也都不能传参#}
    <p>{{ obj }}</p>
    <p>{{ obj.get_cls }}</p>
    <p>{{ obj.get_func }}</p>
    <p>{{ obj.get_self }}</p>
    
    {#模板语法取值,这里要注意,django模板语法在获取容器类型内部元素的值的时候,要统一采用句点符的形式取值,也就是(.),不支持别的取值方式#}
    <p>{{ l.1 }}</p>
    <p>{{ l.3 }}</p>
    
    <p>{{ d.username }}</p>
    <p>{{ d.password }}</p>
    <p>{{ d.password.1 }}</p>
        
    {#前面的变量有值就拿值,没值就用后面默认的,前面变量不存在的情况下也是显示后面的默认值#}
    <p>{{ xo|default:'hello' }}
    </body>
    

    过滤器

    django的过滤器的作用有些类似于我们之前学习的函数的内置方法,其用法就是:

    会将|左边的值当做过滤器的第一个参数 ,|右边的当前过滤器第二个参数.

    下面我们介绍几种常用的过滤器

    # login.html
    <body>
    
    {#add,如果两者都是数值会相加,如果都是字符串会拼接#}
    <p>{{ n|add:100 }}</p>
    <p>{{ n|add:'abc' }}</p>
    <p>{{ s|add:'sasahhdasda' }}</p>
        
    {#upper,大写#}    
    <p>{{ n|upper}}</p>
        
    {#lenth,返回前者的长度,常用于容器类的元素#}
    <p>{{ l|length }}</p>
    <p>{{ d|length }}</p>
        
    {#capfirst会把第一个字母大写#}
    <p>{{ s|capfirst }}</p>
        
    {#random,返回列表中随机的一项#}
    <p>{{ l|random }}</p>
    
    {#filesizeformat,会把数值当做文件大小,并转换成最合适的单位,比如MB,比如GB,比如TB#}
    <p>{{ file_size|filesizeformat }}</p>
        
    {#truncatechars,truncatewords 按字符截取和按单词截取#}
    <p>截取10个字符 三个点也算{{ w1|truncatechars:10 }}</p>
    <p>截取10个字符 三个点也算{{ w|truncatechars:10 }}</p>
    <p>安装空格截取单词 三个点不算{{ w1|truncatewords:6 }}</p>
    <p>安装空格截取单词 三个点不算{{ w|truncatewords:6 }}</p>
    <p>安装空格截取单词 三个点不算{{ w2|truncatewords:6 }}</p>
        
    {#切片,支持索引切片#}
    <p>{{ l|slice:'0:5' }}</p>
    <p>{{ l|slice:'0:5:2' }}</p>
        
    {#date,将日期格式化#}
    <p>{{ ctime|date:'Y-m-d' }}</p>
    <p>{{ ctime|date:'Y年/m月' }}</p>
        
    {#safe,语句安全,支持转义,即我们语句中的符合前端的语法会被转义并显示出来,这种写法是前端转义#}
    <p>{{ sss|safe }}</p>
    <p>{{ sss1|safe }}</p>
        
    {#该句是在后端转义完毕之后传到前端的#}
    <p>{{ res }}</p>
    </body>
    
    #view.py
    #这里的login函数还是用上面模板传值的
    

    标签

    django里面的常用标签即if判断和for循环

    # login.html
    
    <body>
    
    {#if...else判断#}
    {% if xo %}
        <p>xo有值</p>
    {% else %}
        <p>xo没有值</p>
    {% endif %}
    
        
    {#if...elif...else#}
    {% if xo %}
        <p>xo有值</p>
    {% elif xo1 %}
        <p>xo1有值</p>
    {% else %}
        <p>去他大爷的</p>
    {% endif %}
    
        
    {#for...#}    
    {% for foo in l %}
        {% if forloop.first %}
            <p>这是我的第一次</p>
        {% elif forloop.last %}
            <p>这是最后一次了啊</p>
        {% else %}
            <p>嗨起来 大宝贝~</p>
        {% endif %}
    {% endfor %}
    
    
        
    {#设置empty,如果循环体xo为空的话,会返回empty里面的内容#}    
    {% for foo in xo %}
        <p>{{ forloop.counter }}:{{ foo }}</p>
        {% empty %}
        <p>你给我的对象是个空的没法进行for循环</p>
    {% endfor %}
    
    
        
    {#对字典里的值进行循环取值,包括items键值对,keys关键字以及values值#}    
    {% for foo in d.items %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    {% for foo in d.keys %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    {% for foo in d.values %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    
    {#对取到的值起一个别名,这样在endwith的结构体里面就可以直接用这个别名来调用#}
    <p>{{ yyy.user_list.2.username.1 }}</p>
    
    {% with  yyy.user_list.2.username.1 as dsb %}
        <p>{{ dsb }}</p>
        <p>{{ yyy.user_list.2.username.1 }}</p>
    {% endwith %}
    </body>
    

    自定义过滤器和标签

    我们在自定义过滤器和标签的时候,要牢记以下三个步骤:

    1. 首先我们要在应用名下新建一个文件夹,名为templatetags,注意,名字不能错,不然django会找不到这个东西以至于自定义的过滤器和标签都不生效

    2. 在刚刚创建的templatetags文件夹下面新建一个py文件,名字任意,我们这里起名字叫做my_tag.py

    3. 在该my_tag.py文件里写入以下两行代码

      # my_tag.py
      from django.template import Library
      
      register = Library()
      

    做完以上三步我们就可以来写自己的过滤器和标签了,同样是在这个my_tag.py文件里写

    自定义过滤器如下:

    # my_tag.py
    @register.filter(name='myplus')	#给过滤器起别名为myplus,调用的时候用别名即可
    def index(a, b):
        return a + b
    # 这个过滤器的作用即是将传入的两个参数相加,然后返回
    # 另外,过滤器最多只能穿两个参数,不能多于两个参数
    

    自定义过滤器的调用:

    # login.html,在前端调用
    <body>
    {% load my_tag %}
    {{ 123|myplus:123 }}
    # 显示的结果为246
    </body>
    

    自定义标签如下:

    # my_tag.py
    @register.simple_tag(name='mysm')
    def login(a, b, c, d):
        return '%s/%s/%s/%s' % (a, b, c, d)
    

    自定义标签的调用:

    # login.html
    <body>
    {% mysm 1 2 3 4 %}
    </body>
    

    要注意的一点是,自定义标签是不能在if判断里面使用的,但是自定义过滤器可以.

  • 相关阅读:
    MySQL乱码问题
    Oracle安装错误“程序异常终止
    Hibernate Spring
    快学Scala 第一课 (变量,类型,操作符)
    Scala 学习笔记之隐式参数和隐式转换并用
    Hadoop 学习笔记之 Incompatible namespaceIDs问题
    Kafka 学习笔记之 Topic日志清理
    Zookeeper 学习笔记之 节点个数
    Kafka 学习笔记之 删除Topic
    Kafka 学习笔记之 架构
  • 原文地址:https://www.cnblogs.com/Xu-PR/p/11728505.html
Copyright © 2020-2023  润新知