10.Django(标模、模板继承、组件、静态文件)

标签

  • 引子

    后端有一个可迭代对象,列表list,元素不固定,将列表里面的每个元素都展示到前端。

  • 重新创建一个流程

  • 通过变量完成需求

    def index(request):
      name = ['名字1', '名字2', '名字3', '名字4']
      return render(request, 'index.html', {'lis': name})
       
       

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
      <h1>测试 测试 测试</h1>
      <ul>
          <li>{{lis.0}}</li>
          <li>{{lis.1}}</li>
          <li>{{lis.2}}</li>
          <li>{{lis.3}}</li>
      </ul>
    </body>
    </html>

    这样写太low,代码写死了,没有拓展性。我们应该根据后端的可迭代对象里面的数据的个数,动态创建前端标签,然后把数据成功替换。Django框架功能强大,它的模板系统已经提供了类似的功能,这个功能就是模板系统里面的另一个功能:标签tags

  • 语法:

    他是支持在前端写for循环以及if判断的。
    {% for foo in 可迭代互相 %}
    逻辑部分
    {% endfor %}
  • for标签

    • 简单示例

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Title</title>
      </head>
      <body>
        <ul>
            {% for i in lis %}
                <li>{{ i }}</li>
            {% endfor %}
        </ul>
      </body>
      </html>
    • 反向循环

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Title</title>
      </head>
      <body>
        <ul>
            {% for i in lis reversed %}
                <li>{{ i }}</li>
            {% endfor %}
        </ul>
      </body>
      </html>
    • 循环字典

      # 打印所有的键名
      <ul>
        {% for key in dic %}
            <li>{{ key }}</li>
        {% endfor %}
      </ul>

      # 打印所有的键名
      <ul>
        {% for key in dic.keys %}
            <li>{{ key }}</li>
        {% endfor %}
      </ul>

      # 打印所有的值
      <ul>
        {% for v in dic.values %}
            <li>{{ v }}</li>
        {% endfor %}
      </ul>

      # 打印所有的键和值,并组成键值对输出
      <ul>
        {% for k,v in dic.items %}
            <li>{{ k }}:{{ v }}</li>
        {% endfor %}
      </ul>
    • 其他功能

      模板系统提供的for循环还提供了一个辅助功能,forloop功能。

      forloop.counter   当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能
      forloop.counter0 当前循环的索引值(从0开始)
      forloop.revcounter   当前循环的倒序索引值(从1开始)
      forloop.revcounter0 当前循环的倒序索引值(从0开始)
      forloop.first 当前循环是不是第一次循环(返回布尔值)
      forloop.last   当前循环是不是最后一次循环(返回布尔值)
      forloop.parentloop 本层循环的外层循环的对象,在通过上面的几个属性来显示外层循环的计数等。

      测试:

      {% for i in lis %}
        <div>{{ forloop.counter }}{{ i }}</div>
      {% endfor %}



      {% for i in lis %}
        <div>{{ forloop.counter0 }}{{ i }}</div>
      {% endfor %}



      {% for i in lis reversed %}
        <div>{{ forloop.revcounter }}{{ i }}</div>
      {% endfor %}


      {% for i in lis reversed %}
        <div>{{ forloop.revcounter0 }}{{ i }}</div>
      {% endfor %}
    • for ... empty ... 组合

      循环的对象如果有内容,不执行empty语句,如果为空,执行empty语句。

      {% for i in lis %}
        <div>{{ i }}</div>
      {% empty %}
        <div>很遗憾,没有查询到内容</div>
      {% endfor %}
  • if标签

    • 语法

      {% if 条件 %}
      	结果 <!-- 不满足条件,不会生成这个标签 -->
      {% elif 条件 %}
      	结果
      {% else %} <!--也是在if标签结构⾥⾯的-->
      	结果
      {% endif %}
    • 测试

      • 示例

      {% if age == 16 %}
          <div>正式花季年龄</div>
      {% elif age == 17 %}
          <div>正式雨季年龄</div>
      {% else %}
          <div>不是花雨季年龄</div>
      {% endif %}
      • 判断条件可以与过滤的功能想结合

      {% if lis|length > 4 %}
          <div>列表元素超过了4个</div>
      {% else %}
          <div>列表元素不足4个</div>
      {% endif %}
      • 条件也可以加逻辑运算符

        if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。

      {% if lis|length > 4 and '名字1' in lis %}
          <div>列表元素超过了4个,并且“名字1”在列表里面</div>
      {% else %}
          <div>列表元素不足4个</div>
      {% endif %}
  • with标签

    类似于起别名。变量名字过长或者变量需要昂贵的代价获取时,我们需要起别名。

    # 方式1:等号两边不要用空格
    {% with vrs=voice_recognition_system %} 
     	<div>{{ vrs }}</div>
     	<p>{{ vrs }}</p>
    {% endwith %}
    
    # 方式2:
    {% with voice_recognition_system as vrs %}
     	<div>{{ vrs }}</div>
     	<p>{{ vrs }}</p>
    {% endwith %}
    
    # 比较昂贵的方式
    {# 前端通过sql想做进⼀步加⼯,获取总个数 #}
    {#{{ sql.count }}#}
    {#<div>{{ sql.count }}</div>#}
    {#<div>{{ sql.count }}</div>#}
    
    {% with stu_num=sql.count %}
     	<div>{{ stu_num }}</div>
     	<div>{{ stu_num }}</div>
     	<div>{{ stu_num }}</div>
     	<div>{{ stu_num }}</div>
    {% endwith %}
  • for标签与id标签的结合使用

    • 示例

      forloop.first 以及 forloop.last都是返回的bool值

      {% for i in lis %}
          {% if forloop.first %}
              <div>第一个元素为{{ i }}</div>
          {% else %}
              <div>{{ forloop.first }}</div>
          {% endif %}
      {% endfor %}

      forloop.parentloop:一定注意!他是返回本次循环外层循环对象,这个对象可以调用forloop的各种方法进行获取响应的数据。

      lis1 = (['A', 'B'], ['C', 'D'], ['E', 'F'])
      
      {% for i in lis1 %}
          {% for j in i %}
              <div>{{ forloop.parentloop.counter }}{{ j }}</div>
          {% endfor %}
      {% endfor %}
  • 注意事项

    1、Django的模板语言不支持连续判断。即不支持一下写法:

    {% if a > b > c %}
    	...
    {% endif %}

    2、Django的模板语言中属性的优先级大于方法(了解)

    def xx(request):
    	d = {"a": 1, "b": 2, "c": 3, "items": "100"}
     	return render(request, "xx.html", {"data": d})

    如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的d.items() 方法,此时在模板语言中:

    {{ data.items }}

    默认会取d的intems key的值。

    {{ dic.items }} 只能获取键对应的值,⽽不能执⾏下⾯的代码
    
    {% for key,values in dic.items %}
    	<div>{{ key }}: {{ values }}</div>
    {% endfor %}
  • csrf_token标签

    我们之前post提交数据时,遇到forbbien错误,当时我们是把setting里面的csrf中间件注销,这样解决不合理,这个一个安全机制。

    重新构建一个流程:

    def login(request):
         if request.method == 'POST':
         print(request.POST.get('username'))
         print(request.POST.get('password'))
         return HttpResponse('登录成功')
         return render(request, 'login.html')

    就是因为这个中间件:csrf_token安全机制

    重写HTML页面:

    <form action="" method="post">
         {% csrf_token %}
         ⽤户名:<input type="text" name="username">
         <p></p>
         密码:<input type="text" name="password">
         <p></p>
         <input type="submit">
    </form>

    再次通过get请求请求页面,执行到views函数,通过render渲染了html页面,最后通过return将最终的渲染过后的html页面返回个浏览器,那么render将{% csrf_token %}渲染成了什么??

    渲染蹭了一个隐藏的input标签

    <input type='hidden' name='csrfmiddlewaretoken'
    value='gYY7y7TbmUzRp5yHaAtiFqLwUO61LvacYZrhzz8lrU5kAqsTI1buvrnFU23QGBb3'
    />

    我们填写完用户名、密码之后。再次提交,直接提交成功了。

    过程:

    并且每次请求登录页面时,隐藏的input标签对应的value值是随机的密文。

    当我们加上此标签之后,再次发出get请求,render返回给我们页面中多了一个隐藏的input标签,并且这个标签里面有一个键值对:

    键:name,值:随机的⼀堆密⽂。 那么这个是干什么用的呢?其实他的流程是这样的:

    第一次发送get请求,在views视图函数返回给你login.html页面你之前,render会将csrf_token标签替换成一个隐藏的input标签,此标签的键值对就是上面那么键值对并且Django将这个键值对保存在内存;当你再次进行post请求时,他会验证你的form表单里面的隐藏的input标签的键值对是否与我内存中存储的键值对相同,如果相同,你是合法的提交,允许通过;如果不相同,则直接返回给你forbidden页面。这就好比说,第一次get请求,他返回给你一个post请求时,必须是从我给你的get请求返回的页面提交的。

    为什么这么做呢?是因为有人登录你的页面时是可以绕过get请求,返回的页面直接进行post请求登录的,比如说爬虫。直接通过requests.post('/login/')直接请求的,这样是没有csrftoken的,这样就直接拒绝了。

    利用爬虫测试:

    ret = requests.post(
         'http://127.0.0.1:8000/login/',
         data={'username': 'taibai', 'password': 123}
    )
    print(ret.content.decode('utf-8'))

     

模板继承

  • 引子

    模板+继承,什么是模板?render渲染一下html页面,形成最终的html页面交由return返回给浏览器,什么是继承?继承为面向对象的三大特性之一,子继承父。模板系统在加上继承的特性。

  • 需求:我们要写四个页面,这四个页面共同好友的内容顶部导航栏以及左侧菜单栏。中间的内容每个页面不同。

    1、重新创建一个项目:

    2、分别构建不同的部分

    urls:

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^base/', views.base),
        url(r'^menu1/', views.menu1),
        url(r'^menu2/', views.menu2),
        url(r'^menu3/', views.menu3),
    ]

    views:

    from django.shortcuts import render
    
    
    # Create your views here.
    
    
    def base(request):
        return render(request, 'base.html')
    
    
    def menu1(request):
        return render(request, 'menu1.html')
    
    
    def menu2(request):
        return render(request, 'menu2.html')
    
    
    def menu3(request):
        return render(request, 'menu3.html')
    

    base页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Bootstrap 101 Template</title>
        <style>
            body{
                margin: 0;
                padding: 0;
            }
            .nav{
                width: 100%;
                height: 50px;
                background-color: black;
                color: white;
                line-height: 50px;
            }
            .nav a{
                color: white;
                text-decoration: none;
                margin-right: 25px;
            }
            .sidebar{
                float: left;
                width: 25%;
                background-color: #575757;
                text-align: center;
                color: white;
                height: 1000px;
            }
            .sidebar a{
                color: white;
                text-decoration: none;
            }
            .menu{
                float: right;
                width: 75%;
            }
        </style>
    </head>
    <body>
    <div class="nav">
        <a href="">普通⼤堂</a>
        <a href="">盆⼉堂</a>
        <a href="">搓澡</a>
        <a href="">捏脚刮痧拔罐</a>
        <a href="">推油</a>
        <a href="">特叔服务</a>
        <input type="text"> ⾼级检索
    </div>
    
    <div class="sidebar">
        <ul type="none">
            <li><a href="/menu1/">菜单⼀</a></li>
            <li><a href="/menu2/">菜单⼆</a></li>
            <li><a href="/menu3/">菜单三</a></li>
        </ul>
    </div>
    
    <div class="menu">
     base的⾸⻚
    </div>
    </body>
    </html>
    
    
    # 其他页面只有menu内容变化了其他没变

    我们通过分析这些html页面,发现了大量的重复代码,太low了,有没有一种解决方式简化我们的代码呢?

     

     

    3、母版示例

    创建一个模板index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Bootstrap 101 Template</title>
        <style>
            body{
                margin: 0;
                padding: 0;
            }
            .nav{
                width: 100%;
                height: 50px;
                background-color: black;
                color: white;
                line-height: 50px;
            }
            .nav a{
                color: white;
                text-decoration: none;
                margin-right: 25px;
            }
            .sidebar{
                float: left;
                width: 25%;
                background-color: #575757;
                text-align: center;
                color: white;
                height: 1000px;
            }
            .sidebar a{
                color: white;
                text-decoration: none;
            }
            .menu{
                float: right;
                width: 75%;
            }
        </style>
    </head>
    <body>
    <div class="nav">
        <a href="">普通⼤堂</a>
        <a href="">盆⼉堂</a>
        <a href="">搓澡</a>
        <a href="">捏脚刮痧拔罐</a>
        <a href="">推油</a>
        <a href="">特叔服务</a>
        <input type="text"> ⾼级检索
    </div>
    
    <div class="sidebar">
        <ul type="none">
            <li><a href="/menu1/">菜单⼀</a></li>
            <li><a href="/menu2/">菜单⼆</a></li>
            <li><a href="/menu3/">菜单三</a></li>
        </ul>
    </div>
    
    <div class="menu">
    
    </div>
    </body>
    </html>

    其余的四个页面全都继承模板,在页面的最顶端写上:

    {% extends 'index.html' %}

     

     

    4、自定制效果

    我们不能所有的内容都继承父类的内容,每个页面都应该有一些自己的个性化的设置。我们可以在母版的相应的位置设置钩子block,然后在不同的页面进行相应的替换。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Bootstrap 101 Template</title>
        <style>
            body{
                margin: 0;
                padding: 0;
            }
            .nav{
                width: 100%;
                height: 50px;
                background-color: black;
                color: white;
                line-height: 50px;
            }
            .nav a{
                color: white;
                text-decoration: none;
                margin-right: 25px;
            }
            .sidebar{
                float: left;
                width: 25%;
                background-color: #575757;
                text-align: center;
                color: white;
                height: 1000px;
            }
            .sidebar a{
                color: white;
                text-decoration: none;
            }
            .menu{
                float: right;
                width: 75%;
            }
        </style>
    </head>
    <body>
    <div class="nav">
        <a href="">普通⼤堂</a>
        <a href="">盆⼉堂</a>
        <a href="">搓澡</a>
        <a href="">捏脚刮痧拔罐</a>
        <a href="">推油</a>
        <a href="">特叔服务</a>
        <input type="text"> ⾼级检索
    </div>
    
    <div class="sidebar">
        <ul type="none">
            <li><a href="/menu1/">菜单⼀</a></li>
            <li><a href="/menu2/">菜单⼆</a></li>
            <li><a href="/menu3/">菜单三</a></li>
        </ul>
    </div>
    
    <div class="menu">
        {% block content %}
        
        {% endblock content %}
    </div>
    
    </body>
    </html>
    
    
    
    然后去相应的html文件中写入:
    {% block content %}
        <h1>你想写的内容</h1>    备注:可以加标签页可以不加标签
    {% endblock content %}

    钩子不仅仅是可以放在html标签中,还可以放在css,js代码中,只要是前端页面内容都可以设置钩子。我们以css举例:

    index.html页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Bootstrap 101 Template</title>
        <style>
            body{
                margin: 0;
                padding: 0;
            }
            .nav{
                width: 100%;
                height: 50px;
                background-color: black;
                color: white;
                line-height: 50px;
            }
            .nav a{
                color: white;
                text-decoration: none;
                margin-right: 25px;
            }
            .sidebar{
                float: left;
                width: 25%;
                background-color: #575757;
                text-align: center;
                color: white;
                height: 1000px;
            }
            .sidebar a{
                color: white;
                text-decoration: none;
            }
            .menu{
                float: right;
                width: 75%;
            }
    
            {% block title %}
    
            {% endblock title %}
        </style>
    </head>
    <body>
    <div class="nav">
        <a href="">普通⼤堂</a>
        <a href="">盆⼉堂</a>
        <a href="">搓澡</a>
        <a href="">捏脚刮痧拔罐</a>
        <a href="">推油</a>
        <a href="">特叔服务</a>
        <input type="text"> ⾼级检索
    </div>
    
    <div class="sidebar">
        <ul type="none">
            <li><a href="/menu1/">菜单⼀</a></li>
            <li><a href="/menu2/">菜单⼆</a></li>
            <li><a href="/menu3/">菜单三</a></li>
        </ul>
    </div>
    
    <div class="menu">
        {% block content %}
    
        {% endblock content %}
    </div>
    
    </body>
    </html>

    base.html:

    {% extends 'index.html' %}
    {% block content %}
        <h1>你想写的内容</h1>
    {% endblock content %}
    
    {% block title %}
        .nav{
            background-color:red;
        }
    {% endblock title %}

    5、保留母版内容并添加个性化内容

    index母版页面:

    <div class="menu">
        {% block content %}
            <div>这是母版</div>
        {% endblock content %}
    </div>

    只是单独给menu1页面这样设置:

    {% extends 'index.html' %}
    
    {% block content %}
        {{ block.super }}
        菜单1 首页
    {% endblock content %}

    其他页面不变,对比看一下结果

     

     

     

    6、总结

    • 如果你在模板中使用{% extends %}标签,它必须是模板中的第一个标签。

    • 模板中设置的钩子可以在css、js、标签是哪个部分设置,越多越好

    • 结束一个钩子时可以标注次钩子的名字,比如{% endblock content %}这样就可以结束此钩子不至于将其他的block钩子一并结束。

 

组件

模板阶乘一般都是继承主体框架,这里面我们可以分为是三部分,导航条,左侧菜单栏,右侧自定制,那么这三部分就好比是三个组件,模板继承与组件的原理相同,但是他们的格局以及体量是不同的额,模板是由大大小小的多个组件组成的固定搭配,也可以成为前端主体框架,而我们的组件就是一组一组细化的功能。

我们写一个导航栏的组件:nav.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            margin: 0;
            padding: 0;
        }
        .nav{
            width: 100%;
            height: 50px;
            background-color: black;
            color: white;
            line-height: 50px;
        }
        .nav a{
            color: white;
            text-decoration: none;
            margin-right: 25px;
        }
    </style>
</head>
<body>
<div class="nav">
    <a href="">普通⼤堂</a>
    <a href="">盆⼉堂</a>
    <a href="">搓澡</a>
    <a href="">捏脚刮痧拔罐</a>
    <a href="">推油</a>
    <a href="">特叔服务</a>
    <input type="text"> ⾼级检索
</div>
</body>
</html>

测试一个页面sub.html。去引用这个组件

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% include 'nav.html' %}

    <h1>你好,世界</h1>
</body>
</html>

 

 

静态文件

css、js是需要单独文件存放的,还有bootstrap的插件,jQuery的插件,视频,图片,音频等等文件,应该统一放在一个目录下,那么我完成一个静态文件的设置。

1、重新创建一个项目static_pro,创建一个专门放置静态文件的文件夹。

2、构建css文件以及html页面:

body {
     margin: 0;
     padding: 0;
}
.nav {
     width: 100%;
     height: 50px;
     background-color: black;
     color: white;
     line-height: 50px;
}
.nav a {
     color: white;
     text-decoration: none;
     margin-right: 25px;
}





<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="nav">
     <a href="">普通⼤堂</a>
     <a href="">盆⼉堂</a>
     <a href="">搓澡</a>
     <a href="">捏脚刮痧拔罐</a>
     <a href="">推油</a>
     <a href="">特叔服务</a>
     <input type="text"> ⾼级检索
</div>

<h1>你好,世界</h1>
</body>
</html>

你会发现,请求失败了。

我们现在基于Djangp给我们提供的框架构建项目,一切就要按照Django的要求来,你要想引用静态文件,必须在settings里面设置配置。

 

 

3、配置srttings

STATIC_URL = '/static/'  #要是没有这个就要补上


STATICFILES_DIRS = [
	os.path.join(BASE_DIR, 'jingtaiwenjian'), # 静态⽂件名随便起
]

4、更改index页面的引用css的方式:

<link rel="stylesheet" href="/static/nav.css">

5、别名static

为什么要起别名?

  • 使用别名代替真实的静态文件名字,防止有人对你的静态文件发起恶意攻击,保证静态文件的安全。

    我们通过这个用别名加密的路径可以直接访问资源:

    我们使用别名伪装的路径可以获取到相应的文件,但是通过这个伪装的路径不能对文件进行破坏,因为路径是通过别名伪装的,假的。

  • 使用别名为了具有拓展性。

    假如你的项目静态文件的名称改掉了,如果说你不是用别名引用的文件,而是真实的路径,凡是涉及到所有的应用的路径全部都需要更改。

    <link rel="stylesheet" href="/jingtaiwenjian/nav.css">
    <link rel="stylesheet" href="/jingtaiwenjian/nav.js">
    <link rel="stylesheet" href="/jingtaiwenjian/jquery.js">
    ......
  •  

posted @ 2020-05-19 10:50  牧羊小董  阅读(212)  评论(0)    收藏  举报