• Django进阶(二)


    Template

    之前的好多HTML文件中都包含类似“{{ }}”、“{% %}”,其实他们都是模板语言,模板本质上是HTML,但是夹杂了一些变量和标签,可以方便后端的修改前端的内容,而前端代码不用改变。

    模板的组成:HTML代码+逻辑控制代码

    变量:(使用双大括号来引用变量)语法格式:       {{var_name}}

    实例一

    新建项目:mysit,app名:blog,实现功能:后台获取当前年月日,返回给页面显示

    mysit/mysit/urls.py

    from django.conf.urls import url, include
    # 导入include模块
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^blog/', include("blog.urls"))  # 所有以blog开头的地址都去bolg app的urls中找对应的视图函数
    ]

    mysit/templates新建myhtml2.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {{ year }}年{{ month }}月{{ day }}日
    </body>
    </html>

    mysit/blog/urls.py

    from django.conf.urls import url
    from blog import views
    
    urlpatterns = [
    
        url(r'index2/$', views.myhtml2),
        # 所有blog开头的网址都会找到该py 网址最后是index2则对应views.myhtml2函数
    
    ]

    mysit/blog/views.py

    from django.shortcuts import render, HttpResponse, redirect
    
    import datetime
    
    
    def myhtml2(request):
        # 获取当前年月日
        year = datetime.datetime.now().year
        month = datetime.datetime.now().month
        day = datetime.datetime.now().day
        # 方法一
        #  {"year": year, "month": month, "day": day} 键对应myhtml2.html中{{}}内的参数,名称必须一样
        # return render(request, "myhtml2.html", {"year": year, "month": month, "day": day})
        # 方法二
        #  locals()代表将该函数内的所有变量传递给myhtml2.html,变量名必须相同
        return render(request, "myhtml2.html",locals())

    HTML中的“{{ }}”内包含的是变量名称,所需数据由后端提供

    获取属性的万能句点.

    在到目前为止的例子中,我们传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象

    在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。

    实例二

    mysit/templates/myhtml2.html修改如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {{ time.year }}年{{ time.month }}月{{ time.day }}日
    </body>
    </html>

    mysit/blog/views.py修改如下:

    from django.shortcuts import render, HttpResponse, redirect
    
    import datetime
    
    
    def myhtml2(request):
        # 方法一
        # 获取当前时间对象,有属性.year .month .day 分别获取年月日 
        # HTML中获取数据  根据   {{ time.year }}年{{ time.month }}月{{ time.day}}日
        # time = datetime.datetime.now()
        
        # 方法二
        # 获取当前时间对象,分别获取年月日添加到列表中
        # HTML中获取数据  根据  {{ time.0 }}年{{ time.1 }}月{{ time.2}}日
        # time = [ datetime.datetime.now().year,  datetime.datetime.now().month,
        #          datetime.datetime.now().day]
        
        # 方法三
        # 获取当前时间对象,分别获取年月日添加到字典中
        # HTML中获取数据  根据   {{ time.year }}年{{ time.month }}月{{ time.day}}日
        time = {"year": datetime.datetime.now().year, "month": datetime.datetime.now().month,
                "day": datetime.datetime.now().day}
    
        return render(request, "myhtml2.html", locals())

    所以在模板语言中句点(.)可以获取任意对象的任意属性

    变量过滤器

    # 语法格式:      {{obj|filter:param}}
    
    # value1 = "aBcDe"
    # HTML代码: value1|upper
    # 执行结果: ABCDE
    
    # value3 = 'he  llo wo r ld'
    # HTML代码: value3|cut:'he'
    # 执行结果: llo wo r ld
    
    # date 格式化日期字符串
    # value4 = datetime.datetime.now()
    # HTML代码: value4|date:'Y-m-d'
    # 执行结果: 2016-11-29
    
    # value5 = []
    # HTML代码: value5|default:'空的'
    # 执行结果: 空的
    
    # value6 = '<a href="#">跳转</a>'
    # HTML代码: value6|safe
    # 执行结果: 跳转
    
    # HTML代码: value6|striptags
    # 执行结果: 跳转
    
    # value7 = '1234'
    # HTML代码: value7 | filesizeformat
    # 执行结果: 1.2 KB
    
    # HTML代码: value7 | first
    # 执行结果: 1
    
    # HTML代码: value7 | length
    # 执行结果: 4
    
    # HTML代码: value7 | slice: ":-1"
    # 执行结果: 123
    
    # value8 = 'http://www.baidu.com/?a=1&b=3'
    # HTML代码: value8|urlencode
    # 执行结果: http%3A//www.baidu.com/%3Fa%3D1%26b%3D3

    模板标签     标签(tag)的使用(使用大括号和百分比的组合来表示使用tag)  {% tag %}

    ------------------------{%url   "name"   %}:引用路由配置的地址

    <form action="{% url "aaa"%}" >   #代表该表单提交的数据会交给 urls.py中 别名为 “aaa” 所对应的视图函数去执行
              <input type="text">
              <input type="submit"value="提交">
              {%csrf_token%}
    </form>

    ------------------------{%csrf_token%}:用于生成csrf_token的标签,用于防治跨站攻击验证。注意如果你在视图函数中用的是render_to_response返回页面的方法,则该标签不会生效

    其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。

    实例三

    在实例一的基础上

    mysit/templates/myhtml2.html修改如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action={% url "aaa" %} method="post"> # 在urls.py中找到别名为“aaa”所对应的函数提交数据
        <input type="submit">
    </form>
    
    </body>
    </html>

    mysit/blog/urls.py

    from django.conf.urls import url
    from blog import views
    
    urlpatterns = [
    
        url(r'index2/$', views.myhtml2, name="aaa"),
        # 所有blog开头的网址都会找到该py 网址最后是index2 则对应views.myhtml2函数,提交表单,因为其别名为aaa,所以提交表单时执行views.myhtml2函数
    
    ]

    运行,点击提交按钮你会发现以下错误

    Forbidden (403)
    
    CSRF verification failed. Request aborted.
    Help
    
    Reason given for failure:
    
        CSRF token missing or incorrect.
        
    
    In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
    
        Your browser is accepting cookies.
        The view function passes a request to the template's render method.
        In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
        If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
        The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.
    
    You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
    
    You can customize this page using the CSRF_FAILURE_VIEW setting.

    原因是django为了在用户提交表单时防止跨站攻击所做的保护

    只需在HTML文件的表单中添加{%csrf_token%} 便可以解决问题

    ------------------------if判断{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容

    {% if num >= 100 %}
    
        {% if num > 200 %}
            <p>num大于200</p>
        {% else %}
            <p>num介于100和200之间</p>
       {% endif %}
    
    {% elif num < 100 %}
        <p>num小于100</p>
    
    {% else %}
        <p>num等于100</p>
    
    {% endif %}
    
    
    
    {% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量
    {% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:
    
    {% if obj1 and obj2 or obj3 %} 

    ------------------------for循环{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容

    
    {% for obj in list %}  #代表开始执行该次循环
        <li>{{ obj}}</li>
    {% endfor %}  #代表结束该次循环
    
    
    
    #在标签里添加reversed来反序循环列表:
    
        {% for obj in list reversed %}
        ...
        {% endfor %}
    
    #{% for %}标签可以嵌套:
    
        {% for i in list1 %}
            
             {% for ii in list2 %}
                {{ ii }}
             {% endfor %}
        {% endfor %}
    
    
    #系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量,
    #这个变量含有一些属性可以提供给你一些关于循环的信息
    
    1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1:
    
        {% for item in todo_list %}
            {{ forloop.counter }}: {{ item }}
        {% endfor %}
    2,forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0
    3,forloop.revcounter 4,forloop.revcounter0
    5,forloop.first当第一次循环时值为True,在特别情况下很有用: {% for object in objects %} {% if forloop.first %}
            <li class="first">
          {% else %}
            <li>{% endif %} {{ object }} </li> {% endfor %} # 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了 # 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它 # Django会在for标签的块中覆盖你定义的forloop变量的值 # 在其他非循环的地方,你的forloop变量仍然可用 #{% empty %} {{li }} {% for i in li %} <li>{{ forloop.counter0 }}----{{ i }}</li> {% empty %}#如果 li是空的可迭代对象 则执行该行代码下的内容 否不执行 <li>this is empty!</li> {% endfor %}

    到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用 Django 模板系统来创建整个 HTML 页面。 这就带来一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?

    解决该问题的传统做法是使用 服务器端的 includes ,你可以在 HTML 页面中使用该指令将一个网页嵌入到另一个中。 事实上, Django 通过刚才讲述的 {% include %} 支持了这种方法。 但是用 Django 解决此类问题的首选方法是使用更加优雅的策略—— 模板继承 。

    本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。

    ------------------------{%block  block_name %}     {% endblock %}

    ------------------------{% extends "HTML_NAME.html" %}

    实例四

    实现下面功能:

    分别新建base.html  menu1.html  menu2.html。menu1.html  menu2.html与base.html一样,只需修改content盒子内的内容

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            .head{
                height: 50px;
                background-color: blue;
            }
            .menu{
                float: left;
                background-color: aqua;
                height: 570px;
                width: 20%;
            }
            .content{
                float: left;
                height: 570px;
                width: 80%;
                background-color: blueviolet;
            }
            .footer{
                height: 53px;
                background-color: blue;
                clear: both;
            }
    
        </style>
    
    </head>
    <body style="margin: 0">
    <div>
        <div class = "head"></div>
        <div>
            <div class = "menu">
            {# 根据url分发系统中的别名进行跳转#}
                <a href="{% url "menu1" %}">菜单一</a><br>
                <a href="{% url "menu2" %}">菜单二</a>
    
            </div>

    <div class = "content">{#menu1.html  menu2.html 在此添加不同的内容#}</div> </div> <div class = "footer"></div> </div> </body> </html>

    views.py代码如下

    from django.shortcuts import render, HttpResponse, redirect
    
    def base(request):
        return render(request, "base.html")
    
    
    def menu1(request):
        return render(request, "menu1.html")
    
    
    def menu2(request):
        return render(request, "menu2.html")

    urls.py代码如下

    from django.conf.urls import url
    from blog import views
    
    urlpatterns = [
        url(r'^blog/base/$', views.base,name="base"),
        url(r'^blog/base/menu1/$', views.menu1,name="menu1"),
        url(r'^blog/base/menu2/$', views.menu2, name="menu2"),
    ]

    点击运行,浏览器输入网址,就会得到想要的效果,你也发现了base.html  menu1.html  menu2.html三个HTML文件有很多的重复代码,那么就让我们用{%block  block_name %}     {% endblock %}和{% extends "HTML_NAME.html" %} 来省略重复代码

    base.html 修改如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            .head{
                height: 50px;
                background-color: blue;
            }
            .menu{
                float: left;
                background-color: aqua;
                height: 570px;
                width: 20%;
            }
            .content{
                float: left;
                height: 570px;
                width: 80%;
                background-color: blueviolet;
            }
            .footer{
                height: 53px;
                background-color: blue;
                clear: both;
            }
    
        </style>
    
    </head>
    <body style="margin: 0">
    <div>
        <div class = "head"></div>
        <div>
            <div class = "menu">
    {#            根据url分发系统中的别名进行跳转#}
                <a href="{% url "menu1" %}">菜单一</a><br>
                <a href="{% url "menu2" %}">菜单二</a>
    
            </div>
    
    
    {#将之前的代码(<div class = "content"> </div>)替换为下面的代码#}
            {% block base %}
    
            {% endblock %}
    {#base 是这个block的名字,之后的子HTML继承的时候也会标注这个名字,用来进行替换。  {% block base %}被替换的内容{% endblock %}  #}
    
        </div>
        <div class = "footer"></div>
    </div>
    </body>
    </html>

      menu1.html  menu2.html修改如下

    {% extends "base.html" %} 
    {#上面这行代码代表继承自base.html#}
    
    
    {#下面这个block代码块里的内容将会代替父HTML(base.html) 里面 名为base的block代码块#}
    
    {% block base %}
        
         <div class = "content">菜单一</div>
        
    {% endblock %}

    点击运行,浏览器输入网址,需求实现,并且比之前减少了很多代码。

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    为什么你需要升级 pip
    将py文件封装为exe
    Kafka原理分析之基础篇
    顶象验证码破解与研究
    优秀学员学习总结分享(三)
    优秀学员学习总结分享(二)
    ES6数组的扩展--Array.from()和Array.of()
    ES6核心特性
    优秀学员学习总结分享(一)
    JavaScript常见的六种继承方式
  • 原文地址:https://www.cnblogs.com/idktp/p/6114460.html
Copyright © 2020-2023  润新知