首页 > 代码库 > Django进阶(二)

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(rindex2/$, 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="http://www.mamicode.com/#">跳转</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=http://www.mamicode.com/"提交">
          {%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(rindex2/$‘, 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 %}

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

 

 

 

 

 

 

 

 

 

Django进阶(二)