zoukankan      html  css  js  c++  java
  • django视图层与模板层

    django视图层与模板层

    一、视图层

    1.1 HttpResponse、render、redirect

    ​ HttpResponse:返回字符串;

    ​ redirect:重定向

    ​ render:返回一个html页面,也可以给模板传值

    ​ render的逻辑原理:

    from django.template import Template,Context
    def index(request):
        res = Template('<h1>{{ user }} </h1>')
        con = Context({'user': {"username": 'xiaohu', 'pwd': '123'}})
        ret = res.render(con)
        print(ret)
        return HttpResponse(ret)
    

    1.2 JsonResponse

    ​ 前后端分离需要使用json格式进行数据传输,后端专门写接口,前端对接口进行调用,获取json格式的字符串,前端利用序列化反序列转换成前端对应的数据类型。

    ​ js常用数据类型:数值类型、字符类型、数组 []、自定义对象 {}、undefined与null、尔值 true false、symbol。

    ​ 前端语法:JSON.stringify --->序列化 ; JSON.parse--->反序列。

    ​ js序列化与反序列化默认对字符串进行ASCII编码,如果有多种文字,需要对默认进行修改:

    import json
    def index(request):
        user = {'username': 'daxiong大好人', 'pwd': '123'}
        json_str = json.dumps(user, ensure_ascii=False)
        return HttpResponse(json_str)
    

    ​ 使用JsonResponse表示:

    from django.http import JsonResponse
    def index(request):
        user = {'username': 'daxiong大好人', 'pwd': '123'}
        return JsonResponse(user, json_dumps_params={'ensure_ascii':False})
    
    

    ​ JsonResponse默认只支持序列化字典,如果想序列化其他类型(json能够支持的类型),需要将safe参数由默认的True改成False。

    from django.http import JsonResponse
        l = [1,2,3,4,5,5,6]
        return JsonResponse(l,safe=False)
    

    ​ 如若想使用js转换不支持的类型数据,可使用元类增加数据类型,例如datetime:

    class MyJsonClass(json.JSONEncoder):
        def default(self,o):
            # 如果o不是json默认能够序列化,就在该方法内给他处理成json能够转的类型
            if isinstence(o,datetime):
                return o.strftime('%Y-%m-%d')
            else:
                super().default(self,o)
                
    d = {'ctime':datetime.today()}
    print(json.dumps(d,cls=MyJsonClass))
    

    1.3 form表单上传文件

    ​ 前端向后端传输form表单,需要使用request.FILES方法,并且将前端的form的enctype由默认的application/x-www-form-urlencoded改成multipart/form-data。

    ​ 前端:

    <body>
        <form action="" method="post" enctype="multipart/form-data">
        </form>
    </body>
    

    ​ 后端:

    def up(request):
        if request.method =="POST":
            print(request.POST)
            print(request.FILES)
            # 获取文件对象
            file_obj = request.FILES.get('myfile')
            print(file_obj.name)
            with open(file_obj.name,'wb') as f:
                for line in file_obj:
                # 推荐写法
    			# for chunk in file_obj.chunks():
                    f.write(chuck)
         return render(request, 'uo.html')
    

    1.4 CBV源码分析

    ​ CBV(Class Based View):基于类的试图。

    ​ 类中有get和post方法,如何实现前端发送什么请求,后端就会触发什么请求呢?

    ​ CBV路由:

    url(r'^reg/',views.MyReg.as_view())
    

    ​ views:

    rom django.views import View
    
    class MyReg(View):
    	def get(self,request):
    		return render(request,'reg.html')
    
        def post(self,request):
    		return HttpResponse("我是MyReg类中post方法")
    

    ​ 源码:

    @classonlymethod
            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)
                    # 对象在查找属性或方法的顺序是先从自己找,再从产生对象的类中找,再去类的父类中找
                return view
            
    
     """重要部分"""
            def dispatch(self, request, *args, **kwargs):
            	# 判断当前请求方式在不在默认的八个请求方式中
                if request.method.lower() in self.http_method_names:
                    # handler = getattr(自己写的类产生的对象,'小写的请求方法(getpost)','获取不到对应的方法就报错')
                    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                    
                    # handler就是自己定义的跟请求方法相对应的方法的函数内存地址
                else:
                    handler = self.http_method_not_allowed
                # 再调用获取到的方法
                return handler(request, *args, **kwargs)  
    

    1.5 django settings源码分析及实际应用

    ​ django的配置文件有两个,一个是暴露给用户可以自定义配置的,一个是默认的全局配置文件。用户指定了就用用户的,用户没有指定就用默认的。

    ​ settings源码:

    settings = LazySettings()
            
            class LazySettings(LazyObject):
                
                def _setup(self, name=None):
                    # os.environ你可以把它看成是一个全局的大字典
                    settings_module = os.environ.get(ENVIRONMENT_VARIABLE)  # 从大字典中取值
                    # settings_module = 'day59.settings'
                    self._wrapped = Settings(settings_module)  # Settings('day59.settings')
            
            class Settings(object):
                def __init__(self, settings_module):  # settings_module = 'day59.settings'
                    for setting in dir(global_settings):  # 循环获取global_settings文件中所有的名字
                        if setting.isupper():  # 在判断名字是否是大写
                            # 如果是大写 利用反射 获取到大写的名字所对应的值  不停地添加到对象中
                            setattr(self, setting, getattr(global_settings, setting))
                    # store the settings module in case someone later cares
                    self.SETTINGS_MODULE = settings_module
                    mod = importlib.import_module(self.SETTINGS_MODULE)  # 'day59.settings'
                    # from day59 import settings
                    # mod 指代的就是暴露给用户的配置文件模块名
                   
                    for setting in dir(mod):  # 循环获取暴露给用户配置文件中所有的名字
                        if setting.isupper():  # 判断是否是大写
                            setting_value = getattr(mod, setting)  # 如果是大写 获取大写的变量名所对应的值
                            setattr(self, setting, setting_value)  # 不停的给对象设置值
    

    二、模板层

    2.1 模板传值

    ​ 传函数名的时候 会自动加括号调用函数 将函数的返回值展示在html页面上,django模板语法不支持函数传参。django模板语法在获取容器类型内部元素的值的时候 统一只采用 句点符(.)。

    ​ views:

    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
    

    ​ login.html:

    <p>{{ n }}</p>
    <p>{{ f }}</p>
    <p>{{ s }}</p>
    <p>{{ l }}</p>
    <p>{{ d }}</p>
    <p>{{ se }}</p>
    <p>{{ t }}</p>
    <p>{{ b }}</p>
    <p>{{ obj }}</p>
    <p>{{l.1 }}</p>
    <p>{{ l.3 }}</p>
    
    <p>{{ d.username }}</p>
    <p>{{ d.password }}</p>
    <p>{{ d.password.1 }}</p>
     <p>{{ func }}</p>
    

    2.2 过滤器

    ​ 过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后再显示,具体语法如下:

    {{ 变量名|过滤器名:传给过滤器的参数 }}
    

    ​ 常用过滤器:

    #1、default
    #作用:如果一个变量值是False或者为空,使用default后指定的默认值,否则,使用变量本身的值,如果
    value=’‘则输出“nothing”
    {{ value|default:"nothing" }}
    #2、length
    #作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那
    么输出是4
    {{ value|length }}
    #3、filesizeformat
    #作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是
    12312312321,输出将会是 11.5 GB
    {{ value|filesizeformat }}
    #4、date
    #作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
    {{ value|date:"Y-m-d" }}
    #5、slice
    #作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg"
    {{ value|slice:"0:2" }}
    #6、truncatechars
    #作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,
    如果value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点
    {{ value|truncatechars:8 }}
    #7、truncatewords
    #作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”
    hello world egon 嘎嘎“,则输出"hello world ..."
    {{ value|truncatewords:2 }}
    #8、safe
    #作用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转义,例如value="
    <script>alert(123)</script>",模板变量{{ value }}会被渲染成
    &lt;script&gt;alert(123)&lt;/script&gt;交给浏览器后会被解析成普通字符”<script>alert(123)
    </script>“,失去了js代码的语法意义,但如果我们就想让模板变量{{ value }}被渲染的结果又语法意义,那么就
    用到了过滤器safe,比如value='<a href="https://www.baidu.com">点我啊</a>',在被safe过滤器处理后
    就成为了真正的超链接,不加safe过滤器则会当做普通字符显示’<a href="https://www.baidu.com">点我啊
    </a>‘
    {{ value|safe }}
    

    2.3 标签

    ​ 标签是为了在模板中完成一些特殊功能,语法为{% 标签名 %},一些标签还需要搭,配结束标签 {% endtag %}。

    ​ for标签:

    #1、遍历每一个元素:
    {% for person in person_list %}
     <p>{{ person.name }}</p>
    {% endfor %}
    #2、可以利用{% for obj in list reversed %}反向循环。
    #3、遍历一个字典:
    {% for key,val in dic.items %}
     <p>{{ key }}:{{ val }}</p>
    {% endfor %}
    #4、循环序号可以通过{{ forloop }}显示
    forloop.counter 当前循环的索引值(从1开始)
    forloop.counter0 当前循环的索引值(从0开始)
    forloop.revcounter 当前循环的倒序索引值(从1开始)
    forloop.revcounter0 当前循环的倒序索引值(从0开始)
    forloop.first 当前循环是第一次循环则返回True,否则返回False
    forloop.last 当前循环是最后一次循环则返回True,否则返回False
    forloop.parentloop 本层循环的外层循环
    #5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子
    句
    {% for person in person_list %}
     <p>{{ person.name }}</p>
    {% empty %}
     <p>sorry,no person here</p>
    {% endfor %}
    
    

    ​ if标签:

    # 1、注意:
    {% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空、或者视
    图没有为其传值的情况下均为False
    # 2、具体语法
    {% if num > 100 or num < 0 %}
     <p>无效</p>
    {% elif num > 80 and num < 100 %}
     <p>优秀</p>
    {% else %}
     <p>凑活吧</p>
    {% endif %}
    #3、if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
    

    ​ with标签:

    # with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次
    都向数据库发送请求来重新获取变量的值
    {% with li.1.upper as v %}
     {{ v }}
    {% endwith %}
    

    2.4 自定义标签和过滤器

    ​ 步骤:

    ​ 1 在应用名下面新建一个templatetags文件夹(必须叫这个名字)

    ​ 2 在改文件夹下 新建一个任意名称的py文件

    ​ 3 在该py文件内 固定先写两行代码

    from django.template import Library
    
    register = Library()
    

    ​ 自定义的过滤器和标签:

    @register.filter(name='myplus')
    def index(a,b):
    	return a + b
    	
    @register.simple_tag(name='mysm')
    def login(a,b,c,d):
        return '%s/%s/%s/%s'%(a,b,c,d)
    

    ​ 区别:标签不能在if中使用:

    {% if 0|myplus:123 %}  可以用
    	<p>有值</p>
    {% endif %}
    
    {% if mysm 1 2 3 4 %}  不能用
    	<p>有值</p>
    {% endif %}
    

    2.5 模板的继承

    ​ 在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、block标签,详解如下:

    #作用:在一个模板文件中,引入/重用另外一个模板文件的内容,
    {% include '模版名称' %}
    
    
    #作用:在一个模板文件中,引入/重用另外一个模板文件的内容
    {% extends "模版名称" %}
    # 也就是说include有的功能extends全都有,但是extends可以搭配一个block标签,用于在继承的基础上定制新的内容,例如css,js,content等,还可以使用.super来继续使用母版上的内容。
    
    

    ​ 1、标签extends必须放在首行,base.html中block越多可定制性越强

    ​ 2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写

    ​ 3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖

    ​ 4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:
    {% block content %}
    ...
    {% endblock content %}
    ​ 5、在一个模版中不能出现重名的block标签。

    2.6 模板的导入

    ​ 当你写了一个特别好看的form表单 你想再多个页面上都使用这个form表单,你就可以将你写的form表单当作模块的形式导入 导入过来之后 就可以直接展示。

    {% include 'good_page.html' %}
    
  • 相关阅读:
    log4j到log4j2升级迁移方案
    WPF InkCanvas 书写毛笔效果
    我是怎么把一个项目带崩的
    Nginx 安装详细(一)
    设计方法小总结
    Node.js event loop 和 JS 浏览器环境下的事件循环的区别
    JavaScript this指向问题
    域名解析问题
    浏览器缓存
    Go项目部署到服务器
  • 原文地址:https://www.cnblogs.com/tangceng/p/11728911.html
Copyright © 2011-2022 走看看