美文网首页Django
05-Django模板

05-Django模板

作者: EndEvent | 来源:发表于2018-07-27 15:46 被阅读939次

    一、模板概述

    • 模板组成

      HTML代码
      动态插入的代码(挖坑、填坑逻辑控制代码)
      
    • 作用

      快速生成HTML页面
      
    • 优点

      模板的设计实现了业务逻辑与现实内容的分离
      视图可以使用任何模板
      
    • 模板处理

      加载
      渲染
      

    二、定义模板

    • 变量

      - 视图传递给模板的数据
      - 变量遵守标识符规则
      - 语法
        {{ var }}
      - 注意
        变量若不存在,则插入空的字符串
      - 点语法
       字典查询、属性或方法、数字索引 
      
    • 标签

      - 语法
        {% tag %}
      - 作用
        在输出中创建文本
        控制逻辑和循环
      
    • 单行注释

        {# 注释内容 #}
      
    • 标签if

      - 语法1
        {% if 条件 %}
            语句
        {% endif %}
      - 语法2
        {% if 条件 %}
            语句1
        {% else %}
            语句2
        {% endif %}
      - 语法3
        {% if 条件 %}
            语句1
        {% elif 条件 %}
            语句2
        {% elif 条件 %}
            语句3
        ....
        {% else %}
            语句
        {% endif %}
      - 例如
        {% if username %}
            欢迎 <span> {{username}} </span> 回来
        {%else%}
            游客登录,新用户注册有惊喜!
        {%endif%}
      
    • 标签for

      - 格式1
        {% for 变量 in 列表 %}
            语句
        {% endfor %}
      - 格式2
        {% for 变量 in 列表 %}
            语句1
        {% empty %}
            语句2
        {% endfor %}
        备注: 列表为空或列表不存在时执行语句2
      - 格式3
        {{forloop.counter}} 表示当前是第几次循环
      - 例如
        {% for student in students %}
            <li>
                我叫{{student.sname}},性别{{student.ssex}},今年{{student.sage}}岁,座右铭:"{{student.sbrief}}"。
            </li>
        {% endfor %}
      - 例如
        <ul>
            {% for name in names %}
                {% if forloop.counter|divisibleby:2 %}
                    <li style="color: red"> {{forloop.counter}} - {{name}} </li>
                {% else %}
                    <li style="color: blue"> {{forloop.counter}} - {{name}} </li>
                {% endif %}
            {% empty %}
                <li> 没有学生喔. </li>
            {% endfor %}
        </ul>
      
    • 标签comment

      - 作用
        多行注释
      - 例如
        {% comment %}
            <p>姓名: {{student.sname}}</p>
            <p>性别: {{student.ssex}}</p>
            <p>年龄: {{student.sage}}</p>
            <p>座右铭: {{student.sbrief}} </p>
        {% endcomment %}
      
    • 标签ifequal、ifnotequal

      - 作用
        判断值1与值2是成立
      - 例如
        {% ifequal 'hello' 'world' %}
            <h1> 喔,hello和world一样呢。 </h2>
        {% endifequal %}
      - 例如
        # return render(request, 'meituan/testtemp.html',{'class1':'python03','class2':'python03'})
        {% ifequal class1 class2 %}
            <p>你们在同一个班级呢。</p>
        {% else %}
            <p>你们是不同班级。</p>
        {% endifequal %}
      
    • 过滤器

      - 作用
        在变量被显示前修改它
      - 语法
        {{ var|过滤器 }}
      - lower 小写
        <h1> {{str|lower}} </h1>
      - upper 大写
        <h1> {{str|upper}} </h1>
      - join 传递参数(参数用引号引住)
        <h1> {{list|join:'#'}} </h1>
      - default 默认值(如果一个变量没有被提供或值为false、空,可以使用默认值)
        <h1> {{username|default:'游客'}} </h1>
      - date 根据给定格式转换日期为字符串
        <h1> {{dateValue|date:'y-m-d'}} </h1>
      
    • 标签inlcude

      - 作用
        加载模板并以标签内的参数渲染
      - 格式
        {% include '模板目录' 参数1 参数2 %}
      - 例如:
        # 不传递参数
        {% include "content.html" %}
        # 传递参数scoreList
        {% include "content.html" with scores=scoreList  %}
      

      由零合一,先完成小细节,最后使用include一起包含进去!

    • 标签url

      - 作用
        反向解析
      - 格式
        {% url 'namespace:name' p1 p2 %}
      

      备注: 具体看下面详细说明。

    • 标签block、extends

      - 作用
        用于模板的继承
      

      备注: 具体看下面详细说明。

    • 标签autoescape

      - 作用
        用于HTML转义
      

      备注: 具体看下面详细说明。

    • 标签csrf_token

      - 作用
        用于跨域请求伪造保护
      - 格式
        {% csrf_token %}
      

      备注: 具体看下面详细说明。

    三、反向解析

    - 反向解析语法
      {% url 'namespace:name' p1 p2 %}
    
    - 项目的urls.py文件中
      url(r'^meituan/', include('app.urls', namespace='app') )
    
    - 应用的urls.py文件中
      # 路由(带参数)  
      url(r'^goods/(\d+)/$',views.goods, name='goods'),
    
      # 视图函数(带参数,和url与之对应)
      def goods(request, page):
        return HttpResponse('商品列表: 第%s页' % page)
      
    
    - 模板(带有参数的)
      <a href="{% url 'app:goods' 3 %}"> 商品列表 </a>
      <a href="{% url 'app:students' student.id %}">{{ student.s_name }}</a>
    
    备注:
      name属性,即是给对对应的url添加一个名字;
      但是使用 name 也存在一定的问题 ,比如在同一个项目中的不同的app中 name 可能会重名;
      Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回;
      当不小心定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间;
      namespace命名空间;
    

    反向解析场景: 正常情况下页面中设置的商品页链接地址都是goods/,而在服务器中路由如果发生一些细微的改变时,那么在页面中所有关于商品页链接地址都需要修改。为此可以使用反向解析解决此问题。

    四、模板继承

    • 作用

      模板继承可以减少页面内容的重复定义,实现页面的复用。
      
    • block标签

      - 作用
        在父木模板中预留区域,子模板去填充
      - 语法
        {% block 标签名 %}
        {% endblock 标签名 %}  
      
    • extends标签

      - 作用
        继承模板,需要写在模板文件的第一行
      - 语法
        {% extends '父模板路径' %}
      
    • 示例(定义父模板)

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        {% block title %}
        {% endblock title %}
        <style>
            #header,#footer{
                height: 300px;
                background: red;
                line-height: 300px;
                color: white;
                text-align: center;
                font-size: 30px;
            }
            #footer{
                background: blue;
            }
        </style>
        {% block style %}
        {% endblock style %}
      </head>
      
      <body>
        <!--父模板(很多页面中,头部和尾部都是一致的)-->
        <div id="header">header</div>
      
        <!--主体内容不同,需要各部分进行填充-->
        <div id="content">
            <!--主体内容不确定,就直接这样写即可-->
            {% block content %}
            {% endblock content %}
      
            <br>
            <br>
            {% block test %}
            {% endblock test %}
        </div>
      
        <div id="footer">footer</div>
      </body>
      
      </html>
      
    • 示例(定义子模板1)

      {% extends 'meituan/base.html' %}
      
      {% block content %}
        <h1> 首页 --- 主体内容 </h1>
        <a href="{% url 'meituan:about' %}">关于我们</a>
      {% endblock content %}
      
    • 示例(定义子模板2)

      {% extends 'meituan/base.html' %}
      
      {% block title %}
        <title>关于我们</title>
      {% endblock title %}
      
      {% block style %}
      <style>
        h2{
            background: black;
            color: white;
        }
      </style>
      {% endblock style %}
      
      {% block content %}
        <h1> about关于我们 </h1>
      {% endblock content %}
      
      <!--继承,可以填充,也可以不填充-->
      {% block test %}
        <h2>我住隔壁,我姓王,你有事情我帮忙。</h2>
      {% endblock test %}
      

    五、HTML转义

    • 问题

      <!--views.py-->
      return render(request,'meituan/test2.html',{'code': '<h1>今天是周一.</h1>'})
      
      <!--HTML转义-->
      {{code}}
      
      <!--问题-->
      将接受到的code当前普通字符串渲染
      
    • 转义

      将接受到字符串当成HTML代码渲染
      <!--方式1-->
      {{code|safe}}
      
      <!--方式2-->
      <!--关闭自动转义-->
      {% autoescape off %}
        {{code}}
      {% endautoescape %}
      

    六、CSRF

    - 跨域请求伪造
        某些恶意网站包含链接、表单、按钮、JS,利用用户登录在浏览器中认证,从而攻击服务
    - 放置CSRF
        在settings.py文件中MIDDLEWARE添加'django.middleware.csrf.CsrfViewMiddleware'
        在form表单中添加 '{% csrf_token %}'
    - 例如
    <form action="{% url 'app:login' %}" method="post">
        {% csrf_token %}
        <input type="text" placeholder="输入验证码" name="text"> <br>
        <input type="submit" value="验证">
    </form>
    

    在没有放置CSRF时,会报错一下错误Forbidden (403) CSRF verification failed. Request aborted. More information is available with DEBUG=True.

    七、验证码

    • 作用
    - 在用户注册、登录页面的使用使用,为了防止暴力请求,减轻服务器的压力
    - 防止CSRF的一种方式
    

    request.session.get["k1"],如果不存在则会报错,为了防止出错可以request.session.get('k1',none)

    • 示例(视图之生成验证码)
    # 验证码
    def verifycode(request):
        # 导入绘图模块
        from PIL import Image,ImageDraw,ImageFont
        # 导入随机函数模块
        import random
        # 文件操作
        import io
    
        # 定义变量,用于图片的背景色、宽、高
        # random.randrange()返回指定递增基数集合中的一个随机数
        bgcolor = (random.randrange(20,100),random.randrange(20,100),random.randrange(20,100))
        width = 100
        heigh = 50
    
        # 创建图片
        image = Image.new('RGB',(width,heigh),bgcolor)
    
        # 创建画笔对象
        draw = ImageDraw.Draw(image)
    
        # 调用画笔的point函数,绘制噪点
        for i in range(0,100):
            xy = (random.randrange(0,width),random.randrange(0,heigh))
            fill = (random.randrange(0,255),255,random.randrange(0,255))
            draw.point(xy,fill=fill)
    
        # 定义验证码的备选值
        str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
    
        # 随机选取4个值作为验证码
        rand_str = ''
        for i in range(0,4):
            rand_str += str[random.randrange(0,len(str))]
    
        # 构建字体对象
        # font = ImageFont.truetype(path) # 指定路径加载字体
        # font = ImageFont.load_default() # 加载一个默认的字体
        # truetype(font=None, size=10, index=0, encoding="", layout_engine=None)
        font = ImageFont.truetype('fonts/Songti.ttc',40)
        # font = ImageFont.truetype('fonts/STXINGKA.ttf',40)
    
        #构建字体颜色
        fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
        fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
        fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
        fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
    
        # 绘制4个字
        # def text(self, xy, text, fill=None, font=None, anchor=None, *args, **kwargs):
        draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
        draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
        draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
        draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)
    
        # 释放画笔
        del draw
    
        # 存入session,用于验证
        request.session['verify'] = rand_str
    
        # 文件操作
        buff = io.BytesIO()
        # 将图片保存在内存中,文件类型png
        image.save(buff,'png')
    
        # 将内存中图片数据返回给客户端,MIME类型为图片类型
        # 直接是返回验证码图片
        return HttpResponse(buff.getvalue(),'image/png')
    

    PIL(Python Imaging Library)是Python一个强大方便的图像处理库,名气也比较大,不过只支持到Python 2.7。Pillow是PIL的一个派生分支,但如今已经发展成为比PIL本身更具活力的图像处理库。目前最新版本是3.0.0。
    ython 3.x 安装Pillow: pip install Pillow

    • 示例(视图之登录)
    # 登录操作
    def verifycodefile(request):
        # 获取到session的flag标志值
        flag = request.session.get("flag", True)
        str = ''
        if flag == False:
            str = "请重新输入"
    
        # 清空session
        request.session.clear()
    
        return render(request, 'meituan/verifycodefile.html', {"flag": str})
    
    • 示例(视图之登录验证码验证)
    # 登录验证
    def verifycodecheck(request):
        # 输入的验证码
        # upper()转为大写
        code1 = request.POST.get('verifycode').upper()
        # session验证码
        code2 = request.session['verify'].upper()
        
        if code1 == code2:  # 验证成功
            return render(request,'meituan/success.html')
        else:   # 重新登录操作
            request.session["flag"] = False
            return redirect('/meituan/verifycodefile/')
    
    • 示例(url管理器)
    urlpatterns=[
        url(r'^verifycode/$',views.verifycode), # 验证码测试
        url(r'^verifycodecheck/$',views.verifycodecheck),    # 验证操作
        url(r'^verifycodefile/$',views.verifycodefile),  # 带验证码登录
    ]
    
    • 示例(模板)
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录 | 验证码测试</title>
    </head>
    <body>
        <!--验证码-->
        <!--默认什么都添加,就是直接显示-->
    
    
        <!--添加登录功能验证-->
        <form action="/meituan/verifycodecheck/" method="post">
            {%csrf_token%}
            <input type="text" name="verifycode" />
            <img src="/meituan/verifycode/" /> <br>
            <input type="submit" value="验证" /> <br>
            <span>{{flag}}</span>
        </form>
    
    </body>
    </html>
    

    相关文章

      网友评论

        本文标题:05-Django模板

        本文链接:https://www.haomeiwen.com/subject/kqjzuftx.html