• Django视图层与模板层


    Django视图层与模板层

    视图层

    JsonResponse

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

    方式一:

    import json
    
    def my_view(request):
        data = ['tank', 'sean', 'jason']
        return HttpResponse(json.dumps(data))
    

    方式二:

    from django.http import JsonResponse
    
    def my_view(request):
        data = ['tank', 'sean', 'jason']
        return JsonResponse(data, safe=False)
    	# 默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象
    
    form表单上传文件

    前端

    <form action="" method="post" enctype="multipart/form-data">
        <input type="file" name="myfile">
        <input type="submit">
    </form>
    

    后端

    def homes(request):
        if request.method == '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.chunks():
                    f.write(line)
    
        return render(request, 'home.html')
    
    render原理

    需要导入两个模块Template,Context

    from django.template import Template,Context
    
    def ab_render(request):
        temp = Template("<h1>{{ user_dic }}{{ user_dic.username }}{{ user_dic.password }}</h1>")
        user_dic = Context({'user_dic': {'username': 'jason', 'password': '123'}})
        res = temp.render(user_dic)
        return HttpResponse(res)
    
    FBV和CBV

    Django的视图层由两种形式构成:FBV和CBV

    1. FBV(Function base view)基于函数的的视图,之前一直都是FBV
    2. CBV(Class base view)基于类的视图

    CBV的基本写法

    urls.py

    from app01 import views
    
    urlpatterns = [
        # CBV路由配置
        url(r'^login', views.MyLogin.as_view()),
        # 必须调用类下的方法as_view
    ]
    

    views.py

    class MyLogin(View):
            def get(self, request):
            return render(request, 'login.html')
    
        def post(self, request):
            name = request.POST.get('name')
            pwd = request.POST.get('pwd')
            if name == 'egon' and pwd == '123':
                res = '登录成功'
            else:
                res = '用户名或密码错误'
            return HttpResponse(res)
    

    login.html

    <form action="" method="post">
        <p>username:<input type="text" name="name"></p>
        <p>password:<input type="text" name="pwd"></p>
        <input type="submit">
    </form>
    

    login提交get请求会自动执行MyLogin中的get方法,提交post请求会自动执行MyLogin中的post方法,为什么能够针对不同的请求能够自动执行对应的方法

    CBV的原理

    在对应关系中:url(r'^login', views.MyLogin.as_view())

    as_view

    • 要么是类中定义的方法(普通函数)@staticmethod

    • 要么是类中定义的绑定类的方法@classmethod

    看源码得知,是绑定给类的方法


    Django配置文件原理

    Django暴露给用户一个可以自定义的配置,但是内部也有默认的配置

    from django.conf import global_settings, settings
    

    点进settings可以看到

    settings = LazySettings() # 这是个基于模块的单例
    # 而 LazySettings()很明显是调用了一个类或函数
    

    点进LazySettings可以看到

    针对在哪里设置了"DJANGO_SETTINGS_MODULE"这个键值对,点进manage.py

    然后在点进LazySettings类中的Settings可以看到

    这里有个小方法importlib

    有两个py文件,a和b
    b在文件夹conf下,写有name = 'jason'
    
    在a中想要获取这个名字可以有两种方法
    

    第一种

    from conf import b
    print(b.name) # jason
    

    第二种

    import importlib
    
    res = 'conf.b'
    md = importlib.import_module(res)
    # 该方法最小单位是模块,不能是模块里面的单个名字
    print(md.name)  # jason
    

    有助于以后看源码


    模板层

    模版语法符号:

    {{ }}		变量相关
    {% %}		逻辑相关
    
    模版语法之传值取值

    Python基本数据类型全部支持传给HTML页面(函数和类也可以传)

    函数和对象会自动加括号调用,但模板语法不支持传参

    后端给HTML页面传值的两种方式

    1. 指名道姓的传
    # 方式一
    return render(request, 'index.html', {'n': 11, 'f': 11.11, 's': 'hello world'})
    
    1. locals()
    # 方式二   locals会将当前名称空间中所有的变量名全部传给HTML页面
    return render(request, 'index.html', locals())
    

    HTML页面中,如何获取到后端传递过来的数据

    {{ 变量名 }} 比如:{{ n }} {{ f }} {{ s }}
    

    取值

    Django模版语法取值,使用句点符,索引,键

    <p>{{ l.2 }}</p>
    <p>{{ d.username }}</p>
    <p>{{ d.password }}</p>
    

    模版语法之过滤器(变量相关)

    过滤器一个 | ,管道符

    左边的会当做过滤器的第一个参数 | 过滤器右边的会当做第二个参数

    |length		求数据长度
    {{ s|length }}		11
    
    |add	加法运算
    {{ n|add:10 }}  {{ s|add:'DSB' }}	21	hello worldDSB
    
    |default	默认值(判断值是否为空)
    {{ b|default:'这个b布尔值是True' }}	True
    
    |truncatechars	截取字符
    {{ s|truncatechars:8 }}		hello...
    
    |truncatewords	截取单词
    {{ s|truncatewords:8 }}		hello world
    
    |filesizeformat	文件大小
    {{ file_size|filesizeformat }}	2.8G
    
    |slice	切片操作
    {{ s|slice:'0:2' }}、{{ s|slice:"0:8:2" }}	he、hlow
    
    |date	日期格式化
    {{ ddd|date:'Y-m-d' }}		2020-01-07
    
    |safe	转义
    {{ res|safe }}	hello(一级标签hello)
    
    转义在后端也可以实现
    from django.utils.safestring import mark_safe
    res2 = mark_safe("<h1>hello</h1>")
    
    {{ res2 }}	hello(一级标签hello)
    

    总结:前端代码不一定非要在前端页面写,可以在后端写好传递给前端页面使用,这样就可以利用到后端更多的逻辑语法


    模板语法之标签(逻辑相关)
    {%  %}
    

    for 循环和if判断

    {% for foo in l %}
        {% if forloop.first %}
            <p>这是第一次</p>
            {% elif forloop.last %}
            <p>这是最后一次</p>
            {% else %}
            <p>{{ foo }}</p>
        {% endif %}
    	{% empty %}
        <p>for循环的对象内部没有值</p>
    {% endfor %}
    

    前端的for循环,对于字典的内置函数,它也有

    {% for foo in d.keys %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    {% for foo in d.values %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    {% for foo in d.items %}
        <p>{{ foo }}</p>
    {% endfor %}
    

    当一个值获取的步骤非常繁琐,但是又需要在很多地方需要用到,我们可以起别名

    {% with d.hobby.1.username.1 as eg %}
    	 <p>{{ eg }}</p>	<!--只能在with体内用-->>
    {% endwith %}
    

    自定义过滤器、标签和inclusion_tag

    先完成以下前期准备工作

    1. 在应用名下新建一个名字必须叫templatetags文件夹
    2. 在该文件夹内新建一个任意名称的py文件(eg:mytag)
    3. 在该文件内 必须先写以下两句代码
    from django.template import Library
    
    register = Library()
    

    自定义过滤器

    # 自定义过滤器
    @register.filter(name='my_sum')
    def index(a, b):
        return a + b
    
    <p>自定义过滤器的使用</p>
    {% load mytag %}
    <p>{{ 10|my_sum:90 }}</p>
    
    100
    
    <p>自定义的过滤器可以在逻辑语句中使用而自定义标签不可以</p>
    {% if 10|my_sum:100 %}
        <p>条件成立</p>
    {% endif %}
    

    自定义标签

    # 自定义标签
    @register.simple_tag(name='my_baby')
    def xxx(a, b, c, d):
        return "%s?%s?%s?%s" % (a, b, c, d)
    
    <p>自定义标签的使用</p>
    {% load mytag %}
    <p>{% my_baby 1 2 3 "hello world" %}</p>
    
    1?2?3?hello world
    

    自定义inclusion_tag

    # 自定义inclusion_tag
    @register.inclusion_tag('demo.html', name='myinc')
    def index1(n):
        l = []
        for i in range(n):
            l.append(i)
        # 将列表传递给demo.html
        return {'data': l}
    
    <p>自定义inclusion_tag的使用</p>
    {% load mytag %}
    {% myinc 7 %}
    
    <!--demo.html-->
    <ul>
        {% for foo in data %}
            <li>{{ foo }}</li>
        {% endfor %}
    </ul>
    

    总结:页面上使用他们,统一先导入load

    {% load mytag %}
    

    模版的继承

    某一个页面大部分区域都是公用的,那这个页面就可以作为模版页面,当别人继承这个页面之后,如何修改对应的区域

    先在模版页面上通过block实现划定区域

    {% block content %}
    {% endblock %}
    

    子页面中先导入整个模版

    {% extends '模版页面.html' %}
    修改特定的区域,通过实现规定好的区域名称
    {% block content %}
    子页面内容
    {% endblock %}
    

    通常情况下,模版页面应该有三块区域

    {% block css %}
    模板页面内容
    {% endblock %}
    {% block content %}	
    模板页面内容
    {% endblock %}
    {% block js %}	
    模板页面内容
    {% endblock %}
    

    例子:

    urls.py

        # 模版的导入
        url(r'^mdzz/', views.mdzz),
        url(r'^loginn/', views.loginn),
        url(r'^reg/', views.register),
    

    views.py

    def mdzz(request):
        return render(request, 'mdzz.html')
    
    def loginn(request):
        return render(request, 'loginn.html')
    
    def register(request):
        return render(request, 'reg.html')
    

    mdzz.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        {% load static %}
        <link rel="stylesheet" href="{% static '/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
        <script src="{% static '/bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    
    
    </head>
    <body>
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>
    
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">Separated link</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>
          <form class="navbar-form navbar-left">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="Search">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
          </form>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">Separated link</a></li>
              </ul>
            </li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
    
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-3">
                <div class="list-group">
                  <a href="/mdzz" class="list-group-item active">
                    首页
                  </a>
                  <a href="/reg" class="list-group-item">注册</a>
                  <a href="/loginn" class="list-group-item">登录</a>
                  <a href="#" class="list-group-item">修改密码</a>
                  <a href="#" class="list-group-item">注销</a>
                </div>
    
            </div>
            <div class="col-md-9">
              <div class="panel panel-primary">
              <div class="panel-heading">
                <h3 class="panel-title">Panel title</h3>
              </div>
              <div class="panel-body">
                {% block content %}
                    <div class="jumbotron">
                  <h1>Hello, world!</h1>
                  <p>...</p>
                  <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
                </div>
    
                {% endblock %}
              </div>
    </div>
    
            </div>
        </div>
    </div>
    </body>
    </html>
    

    loginn.html

    {% extends 'mdzz.html' %}
    
    {% block content %}
    <h2 class="text-center">登录页面</h2>
        <form action="">
        <p>username:
            <input type="text" class="form-control">
        </p>
        <p>password:
            <input type="text" class="form-control">
        </p>
            <input type="submit" class="btn btn-success" value="登录">
        </form>
        {{ block.super }}
    
    {% endblock %}
    

    reg.html

    {% extends 'mdzz.html' %}
    
    {% block content %}
    <h2 class="text-center">注册页面</h2>
        <form action="">
        <p>username:
            <input type="text" class="form-control">
        </p>
        <p>password:
            <input type="text" class="form-control">
        </p>
            <input type="submit" class="btn btn-info" value="注册">
        </form>
        {{ block.super }}
    {% endblock %}
    

    模块的block块越多,可扩展性越高

    还支持子页面调用父页面对应区域的内容,并且可以无限次调用

        {{ block.super }}
    
    模版的导入

    将HTML页面当做模块使用,哪里需要导哪里,这个HTML页面通常不是完整的,只是一0个局部样式

    {% include 'left.html' %}
    
    基于django settings源码实现项目配置文件的 插拔式设计

    自己实现一个类似于Django配置文件

    用户可管理的配置文件(settings)

    NAME = '我是暴露给用户的配置文件'
    

    项目默认的配置文件(global_settings)

    NAME = '我是项目默认的配置文件'
    

    启动文件

    import os, sys
    
    BASE_DIR = os.path.dirname(__file__)
    sys.path.append(BASE_DIR)
    
    if __name__ == '__main__':
        # 项目启动就应该朝全局的大字典中设置键值对
        os.environ['xxx'] = 'conf.settings'
        from lib.conf import settings
        print(settings.NAME)
    

    __init__.py

    import importlib, os
    from lib.conf import global_settings
    
    class Settings(object):
        def __init__(self):
            # 先循环遍历项目默认的全局配置文件
            for name in dir(global_settings):
                # 判断变量名是否是大写
                if name.isupper():
                    # 将键值对设置给对象
                    k = name    # NAME
                    v = getattr(global_settings, name)
                    setattr(self, k, v)
            
            # 先获取暴露给用户的配置文件的字符串路径
            module_path = os.environ.get('xxx')
            # 利用importlib模块导入settings文件
            md = importlib.import_module(module_path)
            
            # 同上
            for name in dir(md):
                # 判断变量名是否是大写
                if name.isupper():
                    # 将键值对设置给对象
                    k = name    # NAME
                    v = getattr(md, name)
                    setattr(self, k, v)
    
    settings = Settings()
    
  • 相关阅读:
    git-将dev代码合并到test
    java中一句话取到用split()截后的最后一个值
    shiro重定向或会话失效后NginxURL地址无效,以及浏览器控制台Mixed Content: The page at ‘https://XXX’ was loaded over HTTPS, but requested an insecure错误
    Linux 查找Nginx配置文件位置命令
    Linux 常用命令(个人暂时用到的)
    代理模式
    【Vue自学笔记(四)】天气案例
    【Vue自学笔记(三)】网络请求的简单使用
    【Vue自学笔记】案例
    【Vue自学笔记(二)】Vue指令
  • 原文地址:https://www.cnblogs.com/YGZICO/p/12198732.html
Copyright © 2020-2023  润新知