django视图层,模板层、插拔式设计、过滤器、标签、模板的继承和导入
一、视图层
视图函数必须要返回一个HttpResponse对象。
FBV和CBV
django的视图层由两种形式构成:FBV和CBV
FBV:基于函数的视图(Function base view)
CBV:基于类的视图(Class base view)
CBV基本写法
from django.views import View class MyLogin(View): def get(self,request): return render(request,'login.html') def post(self,request): return HttpResponse('我是类里面的post方法')
# CBV路由配置 url(r'^login/',views.MyLogin.as_view()), # 等价于 url(r'^login/',views.view) # FBV与CBV在路由匹配上本质是一样的 都是路由与函数内存地址的对应关系
源码:
1.
2.
3.
render原理
def ab_render(request): temp = Template("<h1>{{ user_dict }}{{ user_dict.username }}{{ user_dict.password }}</h1>") user_dict = Context({'user_dict':{'username':'jason','password':123}}) res = temp.render(user_dict) return HttpResponse(res)
插拔式设计
基于django settings源码实现项目配置文件的插拔式设计:
start.py:
import os import sys BASE_DIR = os.path.dirname(__file__) sys.path.append(BASE_DIR) if __name__ == '__main__': # 项目启动 就应该朝全局的大字典中设置键值对 os.environ['xxx'] = 'conf.settings' from lib.conf import settings print(settings.NAME)
lib文件夹下的conf文件夹下的__init__:
import importlib import os from lib.conf import global_settings class Settings(object): def __init__(self): # 先循环遍历项目默认的全局配置文件 for name in dir(global_settings): # 判断变量名是否是大写 if name.isupper(): # 键值对设置给对象 k = name # NAME v = getattr(global_settings,name) # jason setattr(self,k,v) # 先获取暴露给用户的配置文件的字符串路径 module_path = os.environ.get('xxx') # conf.settings # 里面importlib模块 导入settings文件 md = importlib.import_module(module_path) # md = settings # 同上操作 for name in dir(md): # 判断变量名是否是大写 if name.isupper(): # 键值对设置给对象 k = name # NAME v = getattr(md,name) # jason setattr(self,k,v) settings = Settings()
lib文件夹下的conf文件夹下的settings:
NAME = '我是项目默认的配置文件'
conf文件夹下的settings.:
# NAME = '我是暴露给用户的配置文件'
importlib
使用conf下面的b,要想通过b.的方式使用,还可以使用imporlib
# from conf import b # print(b.name) import importlib res = 'conf.b' md = importlib.import_module(res) # 该方法最小单位是模块 不能是模块里面的单个名字 print(md.name) # == print(b.name)
使用conf下面的b,要想通过b.的方式使用,还可以使用imporlib
二、模板层
模板语法的传值
- python基本数据类型全部支持传递给html文件
- 函数
- 类(函数和对象会自动加括号)
import time from datetime import datetime from django.utils.safestring import mark_safe def index(request): # python所有的数据类型都支持传递给html页面 n = 11 f = 11.11 s = 'hello world' l = [1,2,3,4,5,6] d = {"username":'nick','password':123,'hobby':['read',{'username':['bonny','pam']}]} t = (1,2,3,4,5,6,7,) se = {1,2,3,4,5,6} b = True ff = False ss = 'kjasdklas ksdlk akjsdkl da kjda klak d ka dk ska d' sss = '卡时间 冻结 鲨科 技的 卡拉 手动 卡萨 丁卡' file_size = 32213213424 def func(xxx,yyy): print('func被执行了') return 'from func' class MyClass(object): def get_self(self): return 'from self' @staticmethod def get_func(): return 'from func' @classmethod def get_cls(cls): return 'from cls' obj = MyClass() # 1 给模板传递数据 # return render(request,'index.html',{'n':n,'f':f}) # 2 给模板传递数据 ttt = time.time() ddd = datetime.now() res = "<h1>你好啊</h1>" bbb = [] res1 = "<script>alert(123)</script>" res2 = mark_safe("<h1>你好啊</h1>") return render(request,'index.html',locals())
对象:后端给html文件传递数据的两种方式
# 1.指名道姓 return render(request,'index.html',{'n':n,'f':f}) # 2.locals() # 会将当前名称空间中所有的变量名全部传递给html页面 return render(request,'index.html',locals()) # html页面上 如何获取到后端传递过来的数据 # {{ 变量名 }}
取值
django模板语法取值只有一种操作方式:句点符 .
- 点索引
- 点键
模板语法符号
- { { 变量相关 } }
- { % 逻辑相关 % }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <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>函数名会自动加括号执行 展示的是函数的返回值:{{ func }} 模板语法不支持给函数传参</p>#} {#<p>传类名 也会自动加括号实例化{{ MyClass }}</p>#} {#<p>{{ MyClass }}</p>#} {#<p>{{ MyClass.get_func }}</p>#} {#<p>{{ MyClass.get_cls }}</p>#} {#<p>{{ MyClass.get_self }}</p>#} {#<p>{{ obj }}</p>#} {#<p>{{ obj.get_func }}</p>#} {#<p>{{ obj.get_self }}</p>#} {#<p>{{ obj.get_cls }}</p>#} {#<p>取值</p>#} {#<p>{{ l.2 }}</p>#} {#<p>{{ d.username }}</p>#} {#<p>{{ d.password }}</p>#} {#<p>{{ d.hobby.1.username.1 }}</p>#} </body> </html>
过滤器
|length
|add
|default
|truncatechars
|truncatewords
|filesizeformat
|slice
|date
|safe
使用:
<p>过滤器 |左边的会当做过滤器的第一个参数 过滤器名右边的会当做过滤器的第二个参数</p> <p>求数据长度:{{ s|length }}</p> <p>加法运算:{{ n|add:10 }}、{{ s|add:13132 }}、{{ s|add:'DSB' }}</p> <p>默认值(判断值是否为空):{{ b|default:'这个b布尔值是True' }}、{{ ff|default:'这个ff布尔值是Flase' }}</p> <p>截取字符(截取5个字符 三个点也算):{{ s|truncatechars:8 }}</p> <p>截取单词(截取8个单词 三个点不算):{{ ss|truncatewords:8 }}、{{ sss|truncatewords:4 }}</p> <p>文件大小:{{ file_size|filesizeformat }}</p> <p>切片操作:{{ s|slice:'0:2' }}、{{ s|slice:"0:8:2" }}</p> <p>日期格式化:{{ ddd|date:'Y年/m月/d日' }}</p> <p>转义:{{ res|safe }}、{{ res1 }}、后端直接标识安全:{{ res2 }}</p>
前后端取消转义
前端
- |safe
后端
from django.utils.safestring import mark_safe mark_safe('<h1>安全滴</h1>')
总结:前端代码不一定非要在前端页面写,可以在后端写好传递给前端页面使用
标签(逻辑相关)
{#<p>标签</p>#} {#{% for foo in l %}#} {# <p>{{ forloop }}</p>#} {#{% endfor %}#} {#{% for foo in bbb %} <!--l = [1,2,3,4,5,6]-->#} {# {% if forloop.first %}#} {# <p>这是我的第一次</p>#} {# {% elif forloop.last %}#} {# <p>这是最后一次了啊~</p>#} {# {% else %}#} {# <p>{{ foo }}</p>#} {# {% endif %}#} {# {% empty %}#} {# <p>for循环的对象内部没有值</p>#} {#{% endfor %}#} {#{% for foo in d.keys %}#} {# <p>{{ foo }}</p>#} {#{% endfor %}#} {##} {##} {#{% for foo in d.values %}#} {# <p>{{ foo }}</p>#} {#{% endfor %}#} {##} {#{% for foo in d.items %}#} {# <p>{{ foo }}</p>#} {#{% endfor %}#}
当一个值获取的步骤非常繁琐,但是又需要在很多地方用到,我们可以用起别名的方式来简化代码
{#<p>当一个值获取的步骤非常繁琐 但是又需要在很多地方用到 我们可以用起别名的方式来简化代码</p>#} {#{% with d.hobby.1.username.1 as eg %}#} {# <p>别名只能在with内使用:{{ eg }}</p>#} {# <p>{{ d.hobby.1.username.1 }}</p>#} {#{% endwith %}#}
自定义过滤器及标签 inclusion_tag
先完成以下前期准备工作
- 1.在应用名下新建一个名字必须叫templatetags文件夹
- 2.在该文件夹内新建一个任意名称的py文件(eg:mytag)
- 3.在该文件内 必须先写以下两句代码
from django.template import Library register = Library()
自定义过滤器
@register.filter(name='my_sum') def index(a,b): return a + b # 自定义标签 @register.simple_tag(name='my_baby') def xxx(a,b,c,d): return '%s?%s?%s?%s'%(a,b,c,d) # 自定义inclusion_tag @register.inclusion_tag('demo.html',name='myin') def index1(n): l = [] for i in range(n): l.append(i) # 将列表传递给demo.html # return locals() return {'l':l}
<p>自定义过滤器的使用</p> {% load mytag %} <p>{{ 10|my_sum:90 }}</p> <p>自定义标签的使用</p> {% load mytag %} <p>{% my_baby 1 2 3 'hello world' %}</p> <p>自定义的过滤器可以在逻辑语句中而自定义的标签不可以</p> {% if 10|my_sum:100 %} <p>条件成立</p> {% endif %} {% if my_baby 1 2 3 4 %} <p>条件成立</p> {% endif %} <p>自定义inclusion_tag的使用</p> {% load mytag %} {% myin 5 %} # 总结 页面上使用他们 统一先导入 {% load mytag %}
模板的继承
某一个页面大部分区域都是公用的 那这个页面就可以作为模板页面
当别人继承这个页面之后,修改对应的区域.
先在模板页面上通过block实现划定区域
{% block content %}
模板页面内容
{% endblock %}
子页面中先导入整个模板
{% extends '模板页面.html'%}
修改特定的区域 通过实现划定好的区域名称
{% block content %}
子页面内容
{% endblock %}
通常情况下 模板页面页面应该起码有三块区域
{% block css %}
模板页面内容
{% endblock %}
{% block content %}
模板页面内容
{% endblock %}
{% block js %}
模板页面内容
{% endblock %}
# 模板的block块越多 可扩展性越高
还支持子页面调用父页面对应区域的内容 并且可以无限次调用
{{ block.super }}
示例:
模板页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> {% block css %} {% endblock %} </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container-fluid"> <div class="row"> <div class="col-md-3"> <div class="list-group"> <a href="/mdzz/" class="list-group-item active"> 首页 </a> <a href="/register/" class="list-group-item">注册</a> <a href="/loginn/" class="list-group-item">登录</a> <a href="#" class="list-group-item">Porta ac consectetur ac</a> <a href="#" class="list-group-item">Vestibulum at eros</a> </div> </div> <div class="col-md-9"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">Panel title</h3> </div> <div class="panel-body"> {% block content %} <div class="jumbotron"> <h1>Hello, world!</h1> <p>...</p> <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p> </div> {% endblock %} </div> </div> </div> </div> </div> {% block js %} {% endblock %} </body> </html>
子页面
{% extends 'mdzz.html' %} {% block css %} <style> h2 { color: red; } </style> {% endblock %} {% block content %} {% include 'left.html' %} <h2 class="text-center">登录页面</h2> <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-primary"> </form> {{ block.super }} {% endblock %} {% block js %} {# <script>#} {# alert(123)#} {# </script>#} {% endblock %}
{% extends 'mdzz.html' %} {% block css %} <style> h2 { color: green; } </style> {% endblock %} {% block content %} <h2 class="text-center">注册页面</h2> <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> {{ block.super }} {{ block.super }} {{ block.super }} {{ block.super }} {{ block.super }} {{ block.super }} {{ block.super }} {% endblock %} {% block js %} {# <script>#} {# alert(666)#} {# </script>#} {% endblock %}
模板的导入
将html页面当做模块使用 ,哪里需要导哪里 , 这个html页面通常都不是完整的, 只是一个局部样式。
{% include 'left.html' %}
end