视图层

视图层之 HttpResponse 对象

响应对象主要由三种形式

HttpResponse()
redirect()
render()

小白必备三板斧
HttpResponse # 返回字符串

​ redirect # 返回

​ render # 返回 html 文件

​ render() 不仅可以返回 html 文件,还可以给模板传值,通过字典给该页面传递数据,并返回一个渲染后的HttpResponse对象

from django.template import Template, Context

def index(request):
    res = Template("<h1> {{ user}} </h1>")  # 参数表示要渲染的模板样式及对象
    con = Context({"user": {'username': 'jason','password': 123}}) # 被渲染对象具体对应的内容
    ret = res.render(con)
    print(ret)
    return HttpResponse(ret)  #{'username': 'jason', 'password': 123}

  1. JsonResponse

    返回 json格式数据

为什么要给前端返回 json格式字符串:前后端分离,就是基于 json格式传输数据,后端就专门写接口,前端调用你这个接口,就能拿到一个 json 格式的字符串,然后利用序列化反序列化转换成前端对应的数据类型

​ js 常用数据类型:
​ 数值类型
​ 字符类型
​ 数组 []

​ 自定义对象 {}
​ undefined 与 null
​ 布尔值 true, false
​ symbol 标志

前端的 json

JSON.stringify()  序列化 >>> json.dumps
JSON.parse()   反序列化 >>> json.loads

python后端的 json

json.dumps
json.loads
import json
from django.http import JsonResponse

def index(request):
    user = {'username': 'jason你很帅', 'pwd': 123}
    # 1.HttpResponse,使用json转换数据格式
    json_str = json.dumps(user, ensure_ascii=False) # 取消中文转换,默认为True
    # return HttpResponse(json_str) #{"username": "jason", "pwd": 123}

    # 2.使用JsonResponse转换数据格式
    return JsonResponse(user, json_dumps_params={'ensure_ascii': False}) # 取消中文转换

    # l = [1,2,3,4,5,6]
    # return JsonResponse(l, safe=False) #对非字典类型,需要修改 safe参数为 False

总结:HttpResponse序列化数据 需要导入 json模块, 而 JsonResponse可直接对字典类型数据进行序列化操作,对于非字典类型数据需要修改 安全参数 safe=False 后才能转换,而且也是返回给页面,

form 表单上传文件
注意事项

1. 提交方式必须是post
  1. enctype参数必须由默认的 urlencode 变成 formdata,修改后才能上传文件
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="myfile">
    <input type="text" name="password">
    <input type="submit" value="提交">
</form>
def up(request):
    if request.method == 'POST':
        file_obj = request.FILES.get('myfile')
        print(file_obj.name) #考试内容.txt
        with open(file_obj.name, 'wb') as f:
            # for line in file_obj: # file_obj你可以之前看成文件句柄f
            for chunk in file_obj.chunks():
                f.write(chunk)
    return render(request, 'up.html')

注意:form表单上传文件,后端需要在 request.FILES 中获取文件数据,而不再是 POST里面

FBV(Function Based View)基于函数的视图,面向函数式编程

​ CBV(Class Based View) 基于类的视图,面向对象式编程

基于 CBV 的视图(get请求来就会走类里面的 get方法,post请求来就走类里面的 post方法)

​ 需要注意的几点设置:

1. urls.py
url(r'^login/', views.MyLogin.as_view())
  1. views.py(get请求就走get方法,post请求就走post方法)
# CBV 基于类的视图
from django.views import View

class MyReg(View):
    def get(self, request):
        return render(request, 'reg.html')

    def post(self, request):
        return HttpResponse('我是MyReg类中的post方法')


模板层

模板层就是 html 页面,Django系统中的(template)

html 内 接收 views.py 内函数传入的变量, 用 {{ }}接收

模板传值

方式一:通过键值对的形式传参,指名道姓的传参

n = 123
m = [1,2,3]
return render(request, 'login.html', {'n':n, 'm': m}) # 前面的n是参数名, 后面n才是具体的值

方式二:使用 locals()传全部的值

def login(request):
    n = 123
    f = 12.3
    s = '你妹的'
    l = [1,2,3,4,5]
    d = {'name': 'jason', 'pwd': 123}
    t =(1,2,3,4,5,)
    se = {1,2,3,4,5}
    b = True
    
    def func():
        return '你妹的'
    
    class MyClass(object):
        @classmethod
        def get_cls(cls):
            return 'cls'
    obj = MyClass()
    return render(request, 'login.html', locals())
<body>
<p>{{ n }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>
<p>
    {{
    obj.get_cls
    }}
    </p>
</body>

​ 注意事项:
​ 1.传函数给前端的时候,只要再模板层写函数名{{login}},传函数名会自动加()调用用函数,将函数的返回值展示在 html 页面上
​ 2.django 模板语法不支持函数传参
​ 3.django 模板语法在获取容器类型内部元素的值的时候,统一只采用 句点符(.),就是只能通过 ‘点取值’
​ 4.对象也可以传递:{{ 0bj.方法名 }}

模板层的变量

模板语法:分为两大类

{{变量名}} 变量相关
{{% %}}   逻辑相关
<p>字符串:{{ name }}</p>   # 相当于print(name)
<p>数字:{{ age }}</p>   # 相当于print(age)
<p>列表:{{ ll }}</p>  # 相当于print(ll)
<p>元祖:{{ tu }}</p>  # 相当于print(tu)
<p>字典:{{ dic }}</p>   # 相当于print(dic)
{#只写函数名:相当于函数名(),执行该函数#}
<p>函数:{{ test }}</p>     # 相当于print(test())  前端展示函数调用的返回值
{#对象内存地址#}
<p>对象:{{ lxx }}</p>    # 相当于print(lxx)
<p>列表套对象:{{ person_list }}</p>
<p>字典套对象:{{ person_dic }}</p>

模板查询,统一使用句点符 ‘.‘

<p>列表第0个值:{{ ll.0 }}</p>
<p>列表第3个值:{{ ll.3 }}</p>
<p>字典取值:{{ dic.name }}</p>
<p>字典取列表值:{{ dic.ll }}</p>
{#再继续取值,继续点#}
<p>对象取数据属性:{{ lxx.name }}</p>
<p>对象取绑定给对象的函数属性:{{ lxx.get_name }}</p>
<p>对象取绑定给类的函数属性:{{ lxx.cls_test }}</p>
<p>对象取静态方法:{{ lxx.static_test }}</p>
<p>把对象列表中egon年龄取出来:{{ person_list.1.age }}</p>
{#拓展:不能调有参数的方法#}
<p>字符串的方法:{{ name.upper }}</p>

过滤器 (|) :类似于小的方法

过滤器是对 后端 传到 html页面前端的变量进行处理操作,是在 html文件中处理

过滤器的语法:{{ value|filter_name:参数}}

使用管道符 '|' 来应用过滤器

{{需要过滤的数据|过滤器的名字:过滤参数}}

常用的过滤器

  1. default 如果一个变量是 false或者为空,使用给定的默认值。否则,使用变量的值
<p>
    {{value|default:'123'}}
</p>

2.length 返回值的长度,作用于统计字符串和列表的长度

{{value|length}}

3.filesizeformat 将值格式化为一个可读的文件尺寸(例如'13kb','4.1MB',等等)

{{ value|filesizeformat }}

如果 value 是 123456789,输出将会是 117.7 MB

4.slice 切片

{{value|slice:'2:-1'}}  前闭后开区间支持设置步长{{name|slice:'0:3:3'}}

5.date 时间格式化

from datetime import datetime
ctime = datetime.now()
{{ ctime|date:"Y-m-d H:i:s"}}

6.safe 取消转义

前端取消转义可以用 |safe (正常显示出html,js标签样式)

视图层    
xxx='<h1>波波棋牌室</h1>'

模板层
{{xxx|safe}}   #取消转义h1标签就会起作用

后端取消转义

from django.utils.safestring import make_safe
zzz = make_safe(''<h1>啊啊啊啊</h1>')
                
模板层,直接写
{{zzz}}

7.truncatechars 按照指定字符截取内容,截断的字符串以省略号(...)结尾(省略号算3个字符数量)

参数:指定截断的字符数

{{ info|truncatechars:6 }}

8.truncatewords 按空格截取(数字显示的是截取的空格数,三个点不包含)

{{ info|truncatewords:3 }}

9.cut 移除value中所有的与给出的变量相同的字符串

{{ value|cut:' ' }}  #移除 ' '

如果value为'i love you',那么将输出'iloveyou'.

9.add 拼接(数字就相加,字符串就是拼接)

{{ n|add:100 }}
{{ s|add:'hahah 翻车啦' }}

其他过滤器

过滤器 描述 示例
upper 以大写方式输出 {{ user.name | upper }}
add 给value加上一个数值 {{ user.age | add:”5” }}
addslashes 单引号加上转义号
capfirst 第一个字母大写 {{ ‘good’| capfirst }} 返回”Good”
center 输出指定长度的字符串,把变量居中 {{ “abcd”| center:”50” }}
cut 删除指定字符串 {{ “You are not a Englishman” | cut:”not” }}
date 格式化日期
default 如果值不存在,则使用默认值代替 {{ value | default:”(N/A)” }}
default_if_none 如果值为None, 则使用默认值代替
dictsort 按某字段排序,变量必须是一个dictionary
dictsortreversed 按某字段倒序排序,变量必须是dictionary
divisibleby 判断是否可以被数字整除 `{{ 224
escape 按HTML转义,比如将”<”转换为”&lt”
filesizeformat 增加数字的可读性,转换结果为13KB,89MB,3Bytes等 `{{ 1024
first 返回列表的第1个元素,变量必须是一个列表
floatformat 转换为指定精度的小数,默认保留1位小数 {{ 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入
get_digit 从个位数开始截取指定位置的数字 {{ 123456 | get_digit:’1’}}
join 用指定分隔符连接列表 {{ [‘abc’,’45’] | join:’’ }} 返回 abc45
length 返回列表中元素的个数或字符串长度
length_is 检查列表,字符串长度是否符合指定的值 {{ ‘hello’| length_is:’3’ }}
linebreaks 用或 标签包裹变量 {{ “Hi\n\nDavid”|linebreaks }} 返回HiDavid
linebreaksbr 用 标签代替换行符
linenumbers 为变量中的每一行加上行号
ljust 输出指定长度的字符串,变量左对齐 {{‘ab’|ljust:5}}返回 ‘ab ’
lower 字符串变小写
make_list 将字符串转换为列表
pluralize 根据数字确定是否输出英文复数符号
random 返回列表的随机一项
removetags 删除字符串中指定的HTML标记 {{value | removetags: “h1 h2”}}
rjust 输出指定长度的字符串,变量右对齐
slice 切片操作, 返回列表 {{[3,9,1] | slice:’:2’}} 返回 [3,9] `{{ 'asdikfjhihgie'
slugify 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 `{{ '5-2=3and5 2=3'
stringformat 字符串格式化,语法同python
time 返回日期的时间部分
timesince 以“到现在为止过了多长时间”显示时间变量 结果可能为 45days, 3 hours
timeuntil 以“从现在开始到时间变量”还有多长时间显示时间变量
title 每个单词首字母大写
truncatewords 将字符串转换为省略表达方式 `{{ 'This is a pen'
truncatewords_html 同上,但保留其中的HTML标签 `{{ 'This is a pen'
urlencode 将字符串中的特殊字符转换为url兼容表达方式 {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}}
urlize 将变量字符串中的url由纯文本变为链接
wordcount 返回变量字符串中的单词数
yesno 将布尔变量转换为字符串yes, no 或maybe `{{ True

特点:会将 | 左边的当做过滤器的第一个参数, |右边的当做第二个参数

​ 在 Django的模板语法中,通过过滤器来改变变量在页面的显示

​ 前端代码并不一定非要写在前端,也可以在后端写好,传递给前端页面

​ 前后端取消转义
​ 前端: |safe

​ 后端:from django.utils.safestring import make_safe

标签

基本用法:遍历每个元素

for循环标签

视图层:
def test(request):
    l=[1,2,3,4,5]
    return render(request,'login.html',locals())

模板层:
{% for foo in l %}
  {{ foo }}  # 1,2,3,4,5
{% endfor %}


forloop对象,打印forloop可以得到所有循环后的各种信息值
% for foo in l %}
    {{forloop  }}
{% endfor %}

% for foo in l %}
    {% if forloop.first %}
        <p>这是我的第一次</p>
    {% elif forloop.last %}
        <p>这是最后一次了啊</p>
    {% else %}
        <p>嗨起来 大宝贝~</p>
    {% endif %}
{% endfor %}


for...empty
for标签带有一个可选的{% empty %}从句,在给出的循环对象是空或者没有被找到时执行
% for foo in l %}
    <p>{{ forloop.counter }}:{{ foo }} </p>  # 给循环的值编号
    {% empty %}  # 在对象为空或者找不到时被执行
    <p>对象为空,不能循环</p>
{% endfor %}

If 标签

if/elif/else

{% if user_list %}
  用户人数:{{ user_list|length }}
{% elif black_list %}
  黑名单数:{{ black_list|length }}
{% else %}
  没有用户
{% endif %}
{% if user_list|length > 5 %}
  七座豪华SUV
{% else %}
    黄包车
{% endif %}

for循环和判断一起使用

{% for foo in l %}
  {% if forloop.first %}
    这是第一次
    {% elif forloop.last %}
      这是最后一次
    {% else %}
    来啊来啊
  {% endif %}
{% endfor %}

自定义 过滤器

​ 步骤:
​ 1.在应用名下面新建一个templatetags 文件夹(必须交这个名字)
​ 2.在该文件夹下 创建一个任意名称的 py文件
​ 3.在该 py 文件内固定先写两行代码

from django.template import Library

register = Library()
  1. 写一个函数,用@register.filter(name='yyy')装饰一下(可以指定别名)
@register.filter(name='yyy')
def str_add(x,y):
    return x+y

在模板里:(新定定义的标签,过滤器,都要重启程序)
    {% load mytag %}
    {{'lqz'|str_add:'nb'}}

自定义标签

1.在应用名下面新建一个templatetags 文件夹(必须交这个名字)
2.在该文件夹下 创建一个任意名称的 py文件
3.在该 py 文件内固定先写两行代码

from django.template import Library

register = Library()

写一个函数,用@register.simple_tag()装饰(可以指定别名)

@register.simple_tag()
def add_nb(value):
    return value+'nb'

模板中:(多个参数,以空格区分)
{% load mytag %}
{% add_nb 'lqz'%}

模板的继承

当多个页面整体的样式都大差不差的情况下,可以设置一个模板文件,在该母板文件中,使用block块划分多个预期,相当于用block占位,之后子版在使用模板的时候,可以通过block的名字,来区分需要修改哪一部分区域。

模板一般情况下,应该至少有三个被修改的区域:css,子页面的html代码,js

1.使用模板的继承

写一个母版,需要留一个或多个可以扩展的区域。母版中主要是使用空的block完成页面的搭建

{%block 名字 %}
  可以修改的内容
{%endblock%}
母版页面
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Title</title>
  {% block css %}   #母版的css 内容
  
  {% endblock %}
</head>
<body>

<h1>这是母板的标题</h1>

{% block content %}  #母版的content内容

{% endblock %}
<h1>母板底部内容</h1>
{% block js %}      #母版js内容

{% endblock %}
</body>
</html>

在子模板中使用,子模板主要内容是填空母版中空的block

# extends 告诉模板引擎,这个模板继承了另一个模板
{% extends "base.html" %}

{% block 名字 %}
    子模板的内容
{% endblock 名字 %}
{% extends 'home.html' %}
{% block css %}
    <style>
        h1 {
            color: red;
        }
    </style>
{% endblock %}

{% block content %}

    {% include 'beautiful.html' %}
<h1>登陆页面</h1>
    <form action="">
        <p>username:<input type="text" class="form-control"></p>
        <p>password:<input type="text" class="form-control"></p>
        <input type="submit" class="btn btn-danger">
    </form>
{% endblock %}

{% block js %}

{% endblock %}

强调(注意点)

  • 如果母版的block中写了内容,子模板页面没有重写,那么就会使用母版的内容,所以我们在设置母版的block时,一般都是设置空内容。
  • 一旦子模板页面重写了母版的block,往里面写值了,那么就会覆盖掉母版中block的内容
  • 不能在一个模板中定义多个相同的block标签

模板的导入

要反复的使用一个组件,可以将该组件写在一个文件中,在使用的时候导入就可以,在模板中使用

语法

{% include '模板名字' %}
{% include 'beautiful.html' %}