Django框架4
Django框架4
一.render简单实现
from django.shortcuts import render,HttpResponse
from django.template import Template, Context
def db_render(request):
temp = Template("<h1>{{user_dic}}{{user_dic.username}}{{user_dic.password}}</h1>")
user_dict = Context(
{
'user_dic': {
'username': 'jason',
'password': 1123,
}
}
)
res = temp.render(user_dict)
return HttpResponse(res)
结果展示:
二.CBV与FBV
视图函数不一定就是函数,也可以是类
fbv: 基于函数的视图
cbv: 基于类的视图
cbv基本的写法:
from django.views import View
class MyLogin(View):
def get(self, request):
return render(request, 'login_cbv.html')
def post(self, request):
return HttpResponse('我是类里面的post方法')
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.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>
<h2 class="text_center">这里是login_cbv页面</h2>
<form action="" method="post">
<p>
提交 <input type="submit" class="btn btn-primary">
</p>
</form>
</body>
</html>
朝着login_cbv提交get请求时会自动执行MyLogin里面的get方法
而提交post请求也会自动执行MyLogin里面的post方法
为什么MyLogin针对不同的请求方法能够自动执行对应的方法,引入cbv源码
三.CBV源码
研究源码的突破口:
url(r'^login_cbv', view.MyLogin.as_view())
猜想
as_view要么是类里面定义的普通函数 @staticmethod
要么是类里面定义的绑定给类的方法 @classmethod
看到源码发现是类的绑定方法
详细步骤注释图解:
流程详情:
fbv与cbv在路由匹配上本质是一样的
# 首先MyLogin是我们自己创建的类,里面写了get与post方法
# 然后这个类继承了View类,所以调用了View里面的as_view方法
# as_view方法返回的是View类里的闭包函数view的地址值
# 所以url(r'^login/',views.MyLogin.as_view())就相当于:url(r'^login/',views.view)
# 正则匹配到login后,调用view函数,首先生成了一个我们自己创建的类的对象,self,接着给self对象添加属性,再通过对象.属性调用方法dispatch方法,对象以及产生对象的类中没有这个方法,所有调用了父类中的dispatch方法
# 在displatch中首先判断请求的请求方式是否在默认的八大请求方式中,再在对象中找到对应的请求方法post或get,display返回的是请求方式()就是执行了请求方法
所以:
朝着login_cbv提交get请求时会自动执行MyLogin里面的get方法
而提交post请求也会自动执行MyLogin里面的post方法
CBV源码(******)
MyClass.as_view()
# 函数名加括号执行优先级最高
@classonlymethod
def as_view(...):
def view(...):
...
return view
# 变形
url(r'^index/',views.view) # CBV与FBV在路由匹配上本质是一样的
def view(...):
self = cls(...) # 生成的是我们自己写的类的对象
...
return self.dispatch(...)
"""
当你看到self.属性或方法的时候 不要想当然
一定要遵循对象的属性和方法的查询顺序
对象本身 产生对象的类 类的父类
"""
def dispatch(...):
# 先判断当前请求方式是否在默认的八个合法请求方式内
if request.method.lower() in ['get','post','delete','options'...]
# 利用反射获取对象中对应的属性
handler = getattr(self,request.method.lower(),报错信息)
return handler(...) # 执行获取到的方法
四.基于django settings 源码应用到自己的项目中
django暴露给用户一个可以自定义的配置,但是内部也有一个默认的配置
用户配置了就用用户的, 用户没有配置就用默认的
django settings源码
django其实有两个配置文件 一个是暴露给用户的可以自定义的配置 一个是项目默认的配置
用户如果配置了就用用户的 没有配置就用默认的
from django.conf import global_settings,settings
settings = LazySettings()
class LazySettings(...):
def _setup(...):
# 获取暴露给用户的配置文件字符串路径
setting_module = os.environ.get(纯大写变量名)
"""
manage.py
os.environ.setdefault(纯大写变量名,'暴露给用户的配置文件字符串路径')
"""
Settings(setting_module)
def Settings(...)
# 先遍历全局默认的配置文件 给对象设置键值对
for setting in dir(global_settings):
if setting.isupper():
setattr(self,setting,getattr(global_settings,setting))
# 再遍历暴露给用户的配置文件 给对象设置键值对
md = importlib.import_module(setting_module)
for setting in dir(md):
if setting.isupper():
setattr(self,setting,getattr(md,setting))
"""
利用的其实就是字典的键存在和不存在 下面语句的作用
dict[key] = value
"""
五.模板语法的传值
模板语法符号
{{ }} 变量相关
{% %} 逻辑相关
模板层之模板传值
{#模板语法的注释 这个注释前端浏览器检查是看不见的#}
python基本数据类型全部支持传递给html文件
函数与类:
函数和类会自动添加括号执行
函数得到的是函数的返回值,而类得到的是它的对象
模板语法不支持传参
后端给html文件传递数据的两种方式:
1.指名道姓
return render(request, 'index.html', {'n':n, 'm':m})
2.locals() 会将当前名称空间中所有的变量名全部传递给html页面
return render(request, 'index.html', locals())
html页面上 如何获取到后端传递过来的数据
{{变量名}}
取值:
django模板语法取值 只有一种操作方式 句点符
点索引
点键
示例:
<p>{{ l.2 }}</p>
<p>{{ d.username }}</p>
<p>{{ d.password }}</p>
<p>{{ d.hobby.1.username.1 }}</p>
六.过滤器
|... 格式要规范,不可乱加空格
过滤器 |左边的会当做过滤器的第一个参数 过滤器名右边的会当做过滤器的第二个参数
求数据长度:
<p>
{{ s|length }}
</p>
加法运算:
<p>
{{ n|add:12 }}, 两个整型是相加求和
{{ s|add:'da'}} 两个字符串是拼接 如果一个是字符串一个是整型会报错
</p>
默认值(判断值是否为空): 如果前面的值是空,则返回:后面的,如果前面的值不为空,则返回:前面的
<p>
{{ b|default:'这个b布尔值是true'}},
{{ ff|default:'这个ff布尔值是false'}}
</p>
截取字符(截取5个字符 三个点也算):
<p>
{{ s|truncatechars:8 }},
</p>
截取单词 (截取4个单词 三个点不算): 以空格为一个单词结束
<p>
{{ ss|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>
转义:直接传前端语法,为防止恶意脚本,传过去并不执行,
除非后端用mark_safe()来包装一下
或者前端用|safe来表示安全
<p>
{{ res|safe }}, {{res1}},{{res2}}
</p>
ps:前端代码不一定非要在前端页面写,可以在后端写好传递给前端页面使用,这样就可以利用到后端更加多的逻辑语法
七.标签
逻辑相关的
{% for foo in l %}
{% if forloop.first %}
<p>第一次</p>
{% elif forloop.last %}
<p>最后一次</p>
{% else %}
<p>
{{foo}}
</p>
{% endif %}
{% empty %}
<p>
for循环的对象内部没有值
</p>
{% endfor %}
八.自定义过滤器及标签
标签 inclusion_tag
先完成以下前期准备工作
1.在应用名下新建一个名字必须叫templatetags文件夹
2.在该文件内新建一个任意名称的py文件夹(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('test.html', name='myin')
def index1(n):
l=[]
for i in range(n):
l.append(i)
return {'l':l}
使用方法
自定义过滤器的使用
{% load mytag %}
<p>
{{ 10|my_sum:90 }}
</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 %}
自定义inclusion_tag的使用
<p>
{% load mytag %}
{% myin 5 %}
</p>
总结
页面上想要使用他们 要统一导入
{% load mytag %}
九.模板的继承
某一个页面大部分区域是公用的 那这个页面就可以作为模板页面
当别人继承这个页面之后 再修改对应的区域
先在模板页面上通过block实现划定区域
{% block content %}
模板页面的内容
{% endblock %}
子页面中先导入整个模块
{% extends '模板页面.html' %}
修改特定的区域 通过实现划定好的区域名称
{% block content %}
子页面内容
{% endblock %}
通常情况下 模板页面应该起码有三块区域
{% block css %}
模板页面内容
{% endblock %}
{% block content %}
模板页面内容
{% endblock %}
{% block js %}
模板页面内容
{% endblock %}
# 模板的block块越多 可扩展性越高
还支持子页面调用父页面对应区域的内容 并且可以无限次调用
{{ block.super }}
十.模板的导入
将hml页面当做模块来使用 哪里需要倒哪里 这个html页面通常都不是完整的 只是一个局部样式
{% include 'left.html' %}