Django-视图&模版层

一、视图函数

一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应

响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。

无论视图本身包含什么逻辑,都要返回响应

代码写在哪里也无所谓,只要它在你的Python目录下面。

除此之外没有更多的要求了——可以说“没有什么神奇的地方”。

为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

1、视图请求对象

request对象:包含所有的请求信息(浏览器给服务器发过来的是一堆字符串)

1. 属性:
1.1 请求方式:
request.method:获取请求方式(GET/POST) # 地址栏发过来的请求默认都是GET请求;<form mehtod="post">为POST请求
<form action="" method="post"></form>中的action如果为空,默认是往当前页面的url发送请求;如果只写了路径(如 /login/),默认是往当前页面的IP和端口拼接该路径发送请求

1.2 请求数据:
request.GET:获取所有的GET请求信息(字典形式)
request.POST:获取所有的POST请求信息(字典形式)


1.3 http://127.0.0.1:8000/index/?name=1&age=2  GET请求数据中某个值的获取:
request.GET.get("name")
request.GET.get("age")
request.POST.get("xxx") 同理

1.4 request.path:获取请求路径(如:/login/)
"""
url组成:
协议(http):IP:port/路径? get请求数据 ?为分隔符 
如:http://127.0.0.1:8000/index/?name=1&age=2

"""
# 127.0.0.1:8000 也有访问路径,根目录、根路径(/)
# 在url控制器中添加根路径: re_path(r"^$",views.index)
# url控制器中 路径和函数是一对一或多对一的关系

2. 方法:
2.1 request.get_full_path():获取路径和后面的get请求数据

2、视图响应对象  

响应对象主要有三种形式:

一、HttpResponse() :HttpResponse()括号内直接跟一个具体的字符串作为响应体。(html标签也能渲染出来)
二、render() : render(request,template_name[, context])      如:render(request,"index.html",{"timer":ctime})            

              request: 用于生成响应的请求对象。

              template_name:模板文件;要使用的模板的完整名称

              context:可选参数;添加到模板上下文的一个字典。默认是一个空字典。如果第二个参数中的html文件中有模板语法({{}})且字典中的某个值是可调用的,视图将在渲染模板之前调用它。

              render方法就是将一个模板页面中的模板语法({{}})进行渲染,最终渲染成一个html页面作为响应体。

三、redirect() :结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象

  1.传递要重定向的一个硬编码的URL:

def my_view(request):
    ...
    return redirect('/some/url/')

  2. 也可以是一个完整的URL:

def my_view(request):
    ...
    return redirect('http://example.com/') 

二、模版层

templates文件夹下面的文件都叫模板文件;

只不过有的包含模板语法(这种情况下,在把html页面发送给客户端之前,会先有一个解析模板语法的过程)

1、模版语法之变量渲染

project(项目)的 urls.py

from django.contrib import admin
from django.urls import path

from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path(r"index/",views.index) #添加新的记录
]

app01/views.py

from django.shortcuts import render

# Create your views here.

def index(request):
    """
    模板语法只有两个:
    (1)、{{}}  : 用于渲染变量
        1. 深度查询:句点符
        2. 过虑器
    (2)、 {% %} : 用于渲染标签
    :param request:
    :return:
    """

    name = "neo"
    i = 10
    l = [1,2,"a"]
    info = {"name":"neo","age":22}
    b = True

    class Person(object):
        def __init__(self,name,age):
            self.name = name
            self.age = age
    alex = Person("alex",33)
    egon = Person("egon",22)
    person_list = [alex,egon]

    # return render(request,"index.html",{"name":name})
    # 如果变量特别多,可利用 locals():作用就是把所有的局部变量按照字典的形式传到 render()的第三个形参位置;传的方式是按照 {"name":name,"i":i,...}这种方式
    return render(request,"index.html",locals())

  templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>{{ name }}</p>
<p>{{ i }}</p>
<p>{{ l }}</p>
<p>{{ b }}</p>
<p>{{ alex }}</p>
<p>{{ person_list }}</p>
<p>{{ info }}</p>
<hr>

深度查询:利用点来完成
{# 想要列表l的第二个元素: l.1 #}
<p>{{ l.1 }}</p>

{# 获取字典info中name那个key对应的value #}
<p>{{ info.name }}</p>

{# 获取类对象alex的name属性值 #}
<p>{{ alex.name }}</p>

{# 获取person_list列表中第2个类对象的age属性值 #}
<p>{{ person_list.1.age }}</p>

</body>
</html> 

2、模板之过虑器:

project(项目)urls.py

from django.contrib import admin
from django.urls import path

from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path(r"index/",views.index),
    path(r"login/",views.login) #新记录
] 

app01/views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

def index(request):

    # 深度查询:句点符
    name = "neo"
    i = 10
    l = [1,2,"a"]
    info = {"name":"neo","age":22}
    b = True

    class Person(object):
        def __init__(self,name,age):
            self.name = name
            self.age = age
    alex = Person("alex",33)
    egon = Person("egon",22)
    person_list = [alex,egon]

    # 过虑器
    import datetime
    now = datetime.datetime.now()

    empty_list = []
    file_size = 1235467
    str = "hello world"
    text = "Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source."
    link = "<a href='#'>click</a>"

    # 模板之标签
    num = 90

    # return render(request,"index.html",{"name":name})
    # 如果变量特别多,可利用 locals():作用就是把所有的局部变量按照字典的形式传到 render()的第三个形参位置;传的方式是按照 {"name":name,"i":i,...}这种方式
    return render(request,"index.html",locals())

def login(request):
    if request.method == "POST":
        return HttpResponse("OK")
    return render(request,"login.html")  # login.html中含有模板语法,因为有{% csrf_token %};所以发送给客户端之前会先渲染模板语法

 

 templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>{{ name }}</p>
<p>{{ i }}</p>
<p>{{ l }}</p>
<p>{{ b }}</p>
<p>{{ alex }}</p>
<p>{{ person_list }}</p>
<p>{{ info }}</p>
<hr>

{#深度查询:利用点来完成#}
{# 想要列表l的第二个元素: l.1 #}
<p>{{ l.1 }}</p>

{# 获取字典info中name那个key对应的value #}
<p>{{ info.name }}</p>

{# 获取对象alex的name属性值 #}
<p>{{ alex.name }}</p>

{# 获取person_list列表中第2个对象的age属性值 #}
<p>{{ person_list.1.age }}</p>
<hr>

<h3>过虑器</h3>
{# 时间类型会自动给你渲染好格式,如:June 6, 2018, 4:32 p.m. #}
{{ now }}
{# 把上述时间类型通过过虑器转化格式;date是Django提供的过虑器名字,固定的 #}
{{ now|date:"Y-m-d" }}

{#过虑器#}
{# default :如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。#}
{{ empty_list|default:"数据为空" }}
{#length:返回值的长度。它对字符串和列表都起作用。#}
{{ person_list|length }}
{#filesizeformat:将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。#}
<p>{{ file_size|filesizeformat }}</p>
{#date:如果 value=datetime.datetime.now(),同上#}
{#slice:把字符串按照切片的功能进行切割显示(顾头不顾尾)#}
{{ str|slice:"2:-1" }}
{#truncatechars:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾(...也占3个字符)。 参数:要截断的字符数#}
<p>{{ text|truncatechars:20 }}</p>
{#truncatewords:按照单词截取#}
<p>{{ text|truncatewords:6 }}</p>

{#safe:Django的模板中会对HTML标签和JS等语法标签进行自动转义;为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。#}
<p>{{ link }}</p>
{#浏览器效果:<a href='#'>click</a>#}
<p>{{ link|safe }}</p>

{#add:加法;如下:让其加100#}
<p>{{ l.0|add:100 }}</p>
{#upper:转成大写#}
<p>{{ name|upper }}</p>
<hr>

{#标签#}
{#for标签:遍历每一个元素#}
{#i就是l列表中的元素#}
{% for i in l %}
<p>{{ i }}</p>
{% endfor %}
{#可以利用{% for obj in list reversed %}反向完成循环。#}

{#i是info字典中的每个key#}
{% for i in info %}
<p>{{ i }}</p>
{% endfor %}
{#遍历一个字典#}
{% for key,val in info.items %}
<p>{{ key }}:{{ val }}</p>
{% endfor %}

{% for person in person_list %}
<p>{{ person.name }}    {{ person.age }}</p>
{% endfor %}

{#循环序号可以通过{{forloop}}显示;{{forloop}}必须要写在循环内部;forloop.counter是从1开始,forloop.counter0是从0开始 #}
{% for i in l %}
<p>{{ forloop.counter}} {{ i }}</p>
{% endfor %}

{#for...empty:for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。#}
{% for i in empty_list %}
<p>{{ i }}</p>
    {% empty %}
    <p>内容为空</p>
{% endfor %}
{#如果empty_list为空,就会显示{% empty %}后面的 <p>内容为空</p> 标签#}
<hr>
{#if标签:{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。#}
{% if num > 100 or num < 0 %}
    <p>无效</p>
    {% elif num > 80 and num < 100 %}
    <p>优秀</p>
    {% else %}
    <p>凑合吧</p>

{% endif %}

{#with:使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的#}
{% with person_list.1.age as p_age %}
{# 此时 p_age 就代表 person_list.1.age   #}
    {{ p_age }}
    {{ p_age }}
{% endwith %}

{#csrf_token:这个标签用于跨站请求伪造保护#}

</body>
</html>

 templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
{#  csrf_token:这个标签用于跨站请求伪造保护;(可以给当前页面发送POST请求)  #}
    {% csrf_token %}
    <input type="text" name="user">
    <input type="submit">
</form>

</body>
</html>

 模版语法之自定义标签和过滤器

   步骤:

  1. 在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的标签或者过滤器
  2. 在app中创建templatetags模块(模块名只能是templatetags)
  3. 创建任意 .py 文件,如:my_tags.py;在其中定义自己的过滤器和标签
  4. 在使用自定义过滤器的html文件中导入之前创建的 my_tags.py
  5. 使用自定义的过滤器或标签

目录结构

app01/views.py

from django.shortcuts import render

# Create your views here.

def index(request):
    i = 10
    return render(request,"index.html",locals()) #locals 所有变量到html里面

 

app01/templatetags/my_tags_filters.py

from django import template

register = template.Library()   # register的名字是固定的,不可改变

@register.filter
def multi_filter(x,y):
    return x*y
# 一个函数加上装饰器 @register.filter 就变成了一个自定义的过滤器;上述过滤器实现的功能是两个数相乘
# 自定义的过滤器要在模板语法中使用
# 自定义过滤器的局限性:第一个形参是被修饰的变量,第二个形参是过滤器中的参数;过滤器最多只能放两个参数
# 自定义过滤器的优势:进行逻辑判断时,只能用过滤器

# 自定义标签
@register.simple_tag
def multi_tag(x,y):
    return x*y
# 自定义标签无参数个数的限制

 

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>自定义过滤器,标签</h3>
{#在使用自定义的过滤器的html文件中导入之前创建的 my_tags_filters.py#}
{% load my_tags_filters %}
<p>{{ i|multi_filter:20 }}</p>
{#函数multi_filter中有两个形参,所有过滤器multi_filter中要给一个参数,如上面的20#}

{#调用自定义标签#}
<p>{% multi_tag 7 9 %}</p>

{#自定义过滤器的优势#}
{#变量乘以20如果大于100就显示100,否则就显示它本身#}
{% if i|multi_filter:20 > 100 %}
    <p>100</p>
    {% else %}
    <p>{{ i }}</p>
{% endif %}
{#自定义标签不能放到流程控制判断中#}

</body>
</html>

 

模板继承(extends)

模版继承可以让你创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。

目录结构

urls.py

from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path(r'index/',views.index),
    path(r"orders/",views.orders)
]

 

views.py

from django.shortcuts import render

# Create your views here.

def index(request):
    i = 10
    return render(request,"index.html",locals())

def orders(request):
    return render(request,"orders.html")

base.html (需要引入的模板样式;extends 语法) 

<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

    {#再放一个盒子用于重新写title标签;可留多个盒子用于以后扩写内容#}
    {% block title %}
        <title>base</title>
    {% endblock %}
    {# block区域里面本身也可以写内容,如上面的block写入 <title>base</base> ,这样如果引用这个模板时不重写 title这个block,就会默认会使用 block中原有的内容   #}
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .header {
            width: 100%;
            height: 50px;
            background-color: blue;
        }
    </style>
</head>
<body>
{#模板语法之继承#}
<div class="header"></div>

<div class="container">
    <div class="row">
        <div class="col-md-3">
{#            想在这个地方调用advertise.html,就用include语法#}
            {% include "advertise.html" %}

        </div>
        <div class="col-md-9">
            {# 继承:col-md-9 中的内容都删除#}
            {# 在这个地方写一个 block,意味着在这留了一个区域等待别人来重新写 #}
            {% block con %}

            {% endblock %}
        </div>

    </div>
</div>


</body>
</html>

 

orders.html(在其中引入 base.html 这个模板)

{#extends需要放在第一行#}
{#extends标签:用于继承;把 base.html 的样式全都拿过来(头部和左侧栏样式),然后 col-md-9中的内容自己再重新写#}
{% extends "base.html" %}
{#引入过来 base.html的样式之后,需要在 block中填充内容#}
{% block con %}
    {# 重新写自己的内容   #}
    <h4>订单</h4>

{% endblock %}

{#重新写title;放一个HTML的title标签#}
{% block title %}
    <title>orders</title>
{% endblock %}

{#过程:先通过 extends 来继承样式,再通过 block 来填充内容#}
{#继承用于解决HTML代码的复用性#}

 

index.html(include语法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .header {
            width: 100%;
            height: 50px;
            background-color: blue;
        }
    </style>
</head>
<body>
{#模板语法之继承#}
<div class="header"></div>

<div class="container">
    <div class="row">
        <div class="col-md-3">
       {# 想在这个地方调用advertise.html,就用include语法#}
            {% include "advertise.html" %}

        </div>
        <div class="col-md-9">
            <h3>自定义过滤器,标签</h3>
            {#在使用自定义的过滤器的html文件中导入之前创建的 my_tags_filters.py#}
            {% load my_tags_filters %}
            <p>{{ i|multi_filter:20 }}</p>
            {#函数multi_filter中有两个形参,所有过滤器multi_filter中要给一个参数,如上面的20#}

            {#调用自定义标签#}
            <p>{% multi_tag 7 9 %}</p>

            {#自定义过滤器的优势#}
            {#变量乘以20如果大于100就显示100,否则就显示它本身#}
            {% if i|multi_filter:20 > 100 %}
                <p>100</p>
            {% else %}
                <p>{{ i }}</p>
            {% endif %}
            {#自定义标签不能放到流程控制判断中#}
        </div>

    </div>
</div>


</body>
</html>

 

advertise.html(被 index.html引入的内容) 

<div class="action">
    <div class="panel panel-danger">
        <div class="panel-heading">Panel heading without title</div>
        <div class="panel-body">
            111
        </div>
    </div>
    <div class="panel panel-warning">
        <div class="panel-heading">Panel heading without title</div>
        <div class="panel-body">
            222
        </div>
    </div>
    <div class="panel panel-success">
        <div class="panel-heading">Panel heading without title</div>
        <div class="panel-body">
            333
        </div>
    </div>
</div>

 

注意:

如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。

在base模版中设置越多的 {% block %} 标签越好。子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。

如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中

为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:

{% block content %} #开始 content 是名字
...
{% endblock content %} #结束 content 是名字

在大型模版中,这个方法帮你清楚的看到哪一个  {% block %} 标签被关闭了

不能在一个模版中定义多个相同名字的block标签 

posted on 2020-10-09 16:24  I我非柠檬为何心酸I  阅读(165)  评论(0编辑  收藏  举报