视图层,模板层

爷,独闯天下 提交于 2019-12-05 18:56:13

一、视图层(view)

视图函数,本质上就是一个python函数,他接受web请求并返回响应。响应内容可以是HTML网页、重定向、404错误等任何东西,但本质都是返回一个HttpResponse对象。视图函数约定俗成写在view.py文件内

二、请求对象-HttpRequest

request对象 部分常用属性

当一个页面被请求时, django将请求报文中的请求行、首部信息、内容主题封装成HttpRequest类中的属性 。
Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。

1. request.method           #方式,返回的是纯大写的字符串。

2. request.GET              #获取用户提交的get请求数据,返回的是列表套对象。
3. request.GET.get()        #获取列表中的最后一个
4. request.GET.getlist()    #获取列表类型的数据

5. request.POST             #获取用户提交的post请求数据
6. request.POST.get()       #获取列表中的最后一个
7. request.POST.getlist()   #获取列表类型的数据

8. request.FILES            #包含所有的上传文件信息。

注意:FILES 只有在请求的方法为POST 且提交的from表单带有enctype="multipart/form-data"的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。

三、响应对象-HttpResponse

响应形式多种多样,可以是HTML网页、重定向、404错误等任何东西,但本质都是返回一个HttpResponse对象。具体的说响应对象主要有三种形式:HttpResponse、render、redirect

3-1. HttpResponse()

HttpResponse()括号内直接跟一个具体的字符串作为响应体。 即返回字符串

3-2. render()

render(request,template_name,[context])

参数:

  • request:用于生成响应的请求对象。
  • template_name:要使用的模板名称。
  • context:添加到模板上下文的一个字典。默认空字典,如果字典中某个值是可调用的,视图将在渲染模板前调用它。

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

3-3. redirect()

传递要重定向的一个硬编码的URL,即本地的URL文件

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

也可以是一个完整的URL:

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

四、JsonResponse

向前端返回一个json格式字符串的两种方式

# 第一种方式
import json
def my_view(request):
    data=['xxx','yyy']
    return HttpResponse(json.dumps(data))

# 第二种方式
from django.http import JsonResponse
def my_view(request):
    data = ['xxx', 'yyy']
    return JsonResponse(data1,safe=False)
# 默认safe=True代表 只能序列化字典,safe=False代表可以序列化其他数据类型

五、FBV与CBV

FBV基于函数的视图(Function base view)

CBV是基于类的视图(Class base view)

# FBV
# FBV视图层书写方式
def login(request):
    print('我是login函数')
    return render(request,'login.html')


# FBV路由层的书写
url(r'^index/',views.index),



# CBV
# CBV视图层书写方式
from django.views import View
class MyLogin(View):
    def get(self,request):
        print('我是MyLogin里面的get方法')
        return render(request,'login.html')

    def post(self,request):
        print('我是MyLogin里面的post方法')
        return HttpResponse('post')
# CBV路由层的书写
url(r'^login/',views.MyLogin.as_view())

六、 给CBV加装饰器

# 第一种方法:直接书写
class MyLogin(View):
    @outter  # 1.直接写
    def get(self,request):
        print('我是MyLogin里面的get方法')
        return render(request,'login.html')
    @outter  # 1.直接写
    def post(self,request):
        print('我是MyLogin里面的post方法')
        time.sleep(1)
        return HttpResponse('post')


# 第二种使用内置函数,推荐方法
from django.utils.decorators import method_decorator

# 1-1. 内置函数也可以在外面写,并且可以指定给谁装
@method_decorator(outter,name='post')
class MyLogin(View):
    @method_decorator(outter)  # 1-2. 推荐写法
    def get(self,request):
        print('我是MyLogin里面的get方法')
        return render(request,'login.html')

    def post(self,request):
        print('我是MyLogin里面的post方法')
        time.sleep(1)
        return HttpResponse('post')


# 第三种内置函数联合重写dispatch方法

from django.utils.decorators import method_decorator

class MyLogin(View):
    @method_decorator(outter)
    def dispatch(self, request, *args, **kwargs):  
        # 如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截
        return super().dispatch(request,*args,**kwargs)
  
    def get(self,request):
        print('我是MyLogin里面的get方法')
        return render(request,'login.html')
    def post(self,request):
        print('我是MyLogin里面的post方法')
        time.sleep(1)
        return HttpResponse('post')

----------------------------------------------------------

一、模板层(template)

存放在template文件夹下的html文件称之为模板文件,利用模板语法可以在html中展示动态数据,简单来说Django的模板=HTML代码+模板语法

二、模板语法之注释

{# this won't be rendered #}  单行注释

注释多行使用comment标签

三、模板语法之变量

在django模板中遍历复杂数据结构的关键是句点字符,语法:{{ 变量名 }}。变量类似于python中的变量。

变量的命名包括任何字母数字以及下划线("_")的组合。点(".")也有可能会在变量名中出现,不过它有特殊的含义。注意:最重要的是,变量名称中不能有空格或标点符号。

views.py:

name='abc'
age=18
li=[1,2,'3','4']
dic={'name':'abc','age':18,''li:[1,2,4]}
def test():   #函数
    print('abc')
    return 'abchahahah'
class Person():
    def __init__(self,name,age)
        self.name=name
        self.age=age
    def get_name(self):
        return self.name
    @classmethod
    def cls_test(cls):
        return 'cls'
    @staticmethod
    def static_test():
        return 'static'
    ---------
    # 模板里不支持带参数
    def get_name_cs(self,ttt):
        return self.name
    ----------
    
xxx=Person('xxx',18)
yyy=Person('yyy',28)
person_list=[xxx,yyy]

html:

相当于print了该变量

<p>字符串:{{ name }}</p>
<p>数字:{{ age }}</p>
<p>列表:{{ li }}</p>
<p>元祖:{{ tu }}</p>
<p>字典:{{ dic }}</p>
<p>函数:{{ test }}</p>  {#只写函数名:相当于函数名(),返回函数执行结果#}
<p>对象:{{ xxx }}</p>   {#对象内存地址#}

深度查询:

<p>列表第1个值:{{ ll.0 }}</p>
<p>列表第4个值:{{ ll.3 }}</p>
<p>字典取值:{{ dic.name }}</p>
<p>字典取列表值:{{ dic.li }}</p>
<p>对象取数据属性:{{ xxx.name }}</p>
<p>对象取绑定给对象的函数属性:{{ xxx.get_name }}</p>
<p>对象取绑定给类的函数属性:{{ xxx.cls_test }}</p>
<p>对象取静态方法:{{ xxx.static_test }}</p>

四、模板语法之标签

一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 语法为{% tagname %}

模板语法的取值 只有一种方式 统一采用句点符 (.)

4-1. for循环

# 遍历每一个元素
{% for person in person_list %}
    <p>{{ person }}</p>
{% end for%}


# 遍历一个字典:
{% for k,v in dic.items %}
    <p>{{ k }}:{{ v }}</p>

下面是Django为for标签内置的一些属性,可以当作变量一样使用{{ }}在模版中使用。

  • forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号
  • forloop.counter0:循环的当前索引值,从0开始计数;
  • forloop.revcounter: 循环结束的次数(从1开始)
  • forloop.revcounter0 循环结束的次数(从0开始)
  • forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。我们经常要为第一行加点特殊的对待,就用得上这个判断了,结合if。
  • forloop.last:如果这是最后一次循环,则为真
  • forloop.parentloop:对于嵌套循环,返回父循环所在的循环次数

4-2. for...empty

for标签带有一个可选的{% empty %}从句,在给出的组是空的或者没有被找到时执行的操作

注:循环的对象是空,才会走到empty,而不是对象里面的东西为空

{% for person in person_list %}
    <p>{{ person.name }}</p>
    {% empty %}
    <p>sorry,no person here</p>
{% endfor %}

4-3. 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 %}

注:在if标签中使用括号是错误的语法,这点不同于Pythonif语句支持 ,优先级可以使用if嵌套。if支持and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

4-4. 标签实例

# for if联合使用
{% for foo in l %}
    {% if forloop.first %}
        <p>这是我的第一次</p>
    {% elif forloop.last %}
        <p>这是最后一次了啊</p>
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
{% empty %}
    <p>当for循环的对象是空的时候会走</p>
{% endfor %}
        
    
# 模板语法的取值 只有一种方式  统一采用句点符  (.)
comp_dic = {'username':'jason','hobby':['read','study',['run','rap',{'age':18}]]}
# 获取字典嵌套中的age
<p>{{ comp_dic.hobby.2.2.age }}</p>

五、模板语法之过滤器

在Django的模板语言中,通过使用过滤器来改变变量的显示。过滤器的语法: {{ value|filter_name:参数 }}

注意事项

  1. 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
  2. 过滤器可以接受参数,只能接受一个参数
  3. 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
  4. '|'左右没有空格

常用过滤器

1. default

<!-- 如果变量是false或者为空,则使用给定的默认值。-->
{{ value|default:'nothing'}}

2. length

<!-- 返回值的长度,对字符串和列表都起作用-->
value=[1,2,3,4]  
{{ value|length}}   输出是4

3. filesizeformat

<!-- 将值格式化成'人类可读的'文件尺寸。-->
{{1024|filesizeformat}}  输出为1kb

4. safe

<!-- Django模板为了安全默认会对HTML标签和js等语法标签进行转义,有时候我们不希望这些元素被转义,可以通过设置过滤器。-->
script="'<script>alert(111)</script>"
{{ script|safe }}



# 补充:后端也可以利用模块取消转义
from django.utils.safestring import mark_safe
sss2 = "<h2>我的h2标签</h2>"
res = mark_safe(sss2)

5.slice

<!-- 切片,不支持负数 -->
{{ name|slice:'0:3:3' }}

6.truncatechars

<!-- 如果字符串多余指定字符数量,多余会被截断,替换成("...")结尾。 -->
{{ value|truncatechars:9}}

7.truncatewords

<!-- 在一定数量的字后截断字符串。-->
{{ value|truncatewords:9}}

六、自定义标签和过滤器

6-1. 自定义前置准备

  1. 在应用名(app文件夹)下新建一个templatetags包(名字固定),与views.py、models.py等文件在同一目录

  2. 在该文件夹内 新建一个任意名称的.py文件, 如:my_tags.py

  3. 在该.py文件中 必须先写下面两句代码

    from django.template import Library
    register = Library()

6-2. 自定义过滤器

自定义过滤器实际就是一个带有一个或两个参数的python函数

注:函数的第一个参数是要过滤的对象,第二个是自定义参数,函数一共只能有两个参数。

  • 变量的值:不一定是字符串形式
  • 可以有一个初始值,或者不需要这个参数
# 自定义过滤器  跟默认的过滤器一样 最多只能接受两个参数
# 利用register.filter注册并给该过滤器起别名
@register.filter(name='baby')
def index(a,b):
    return a + b


# 自定义过滤器的使用
# 在要使用自定义过滤器的模板文件中导入创建的py文件。语法:{% load 文件名 %}
{% load mytag %}
{{ 1|baby:1  }}
{{ 1|baby:100  }}

# 自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以
{% if mytag '1' '2' '3' '4' %}
    <p>有值</p>
{% else %}
    <p>无值</p>
{% endif %}#

6-3. 自定义标签

除了装饰器,其它步骤与自定义过滤器相似。

过滤器只能有两个参数,自定义标签可以传多个值,空格传值。

注:过滤器可以用在if判断中,标签不能

# 自定义标签   可以接受任意多个参数
# 利用register.simple_tag()注册并给该标签起别名

@register.simple_tag(name='mytag')
def mytag(a,b,c,d):
    return '%s?%s?%s?%s'%(a,b,c,d)

# 自定义标签的使用 可以接受多个参数 参数与参数之间必须空格隔开
{% load mytag %}
    {% mytag 'a' 'b' 'c' 'd' %}

6-4. 自定义inclusion_tag

"""
是一个函数 能够接受外界传入的参数 然后传递给一个html页面
页面上获取数据 渲染 完成之后
将渲染好的页面 放到调用inclusion_tag的地方
"""

# 自定义inclusion_tag
@register.inclusion_tag('mytag.html',name='xxx')
def index666(n):
    l = []
    for i in range(n):
        l.append('第%s项'%i)
        return locals()  # 将l直接传递给mytag.html页面
    
# 自定义inclusion_tag的使用  当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag</p>
{% load mytag %}
    {% xxx 5 %}

七、模板的继承

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

注意:

  1. 模板上的block区域越多 页面的扩展性越强,一个模板页面最好有三块区域:css区域、html代码区域、js区域 html区域可以设置多个block。有了这三块区域,就能够实现每一个页面都有自己独立的css和js代码
  2. 不能在一个模板中定义多个相同名字的block标签
  3. 如果在模板中使用{% extends %}标签,它必须是模板中的第一个标签
# 子模板login.html继承index.html文件模板,全部继承的情况下无法修改内容
# 即login.html中只需要写一句代码
{% extends 'home.html' %}


# 如果子模板需要修改部分,就需要用到 block
# 母模板 index.html
...
<body>
<div id="sidebar">
    # 划定这块区域可以修改,并取别名sidebar
    {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    {% endblock %}
</div>
<div id="content">
    # 划定这块区域可以修改,并取别名content
    {% block content %}{% endblock %}
</div>



# 子模板 login.html
{% extends 'home.html' %}

# 使用block,pycharm会自动提示有哪些区域
{% block sidebar %}
    ...修改内容
</style>
{% endblock %}

{% block content %}
    ...修改内容
{% endblock %}

八、模板的导入

用简单的模板语句解决了重复组件的代码冗余

语法:{% include '模板名称' %}

# 做好注册前提准备,简单的代码可以直接运行imp路径
# imp.html文件内容
{% include 'fr.html' %}

# fr.html文件内容
<p>这是一个特别好看的form表单</p>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!