视图层
-
小白必会三板斧
HttpResponse
render
redirect
视图函数必须有一个返回值 并且返回值的数据类型必须是HttpResponse对象
-
JsonResponse
前后端分离
前后端数据交互 该如何进行?
通常情况下前后端的数据交互采用的都是json的字符串(字典)
后端只需要写好相应的url接口 前端访问你这个接口
你只需要返回一个大字典即可+开发文档
用来告诉前端工程师 你这个接口能够返回那些数据
前后端序列化都用哪些方法
python后端 js
json.dumps JSON.stringify
json.loads JSON.parse
def index(request):
user_dic = {'name':'jason好帅哦 我好喜欢~','password':'123'}
# 如何让json不自动帮你对中文进行转码,把ensure_ascii设置为false,默认的是true
# json_str = json.dumps(user_dic,ensure_ascii=False)
# return HttpResponse(json_str)
# return JsonResponse(user_dic,json_dumps_params={'ensure_ascii':False})
l = [1,2,3,4,5,6,7,] #如果容器类型数据为空的时候 不执行任何语句
# JsonResponse默认是序列化字典用的 如果你想序列化其他数据类型(json模块能够序列化的) 你需要加一个safe参数
return JsonResponse(l,safe=False)
-
FBV与CBV
FBV:是基于函数视图
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有点不同
# FBV写法 路由 >>> 视图函数内存地址
url(r'^index/',views.index),
# CBV写法
url(r'^login/',views.MyLogin.as_view())
-
CBV的源码
为什么CBV能够根据请求的不同 自动执行不同的方法?
访问属性和方法
方法就是函数(函数名加括号执行优先级最高)url(r'^login/',
views.MyLogin.as_view()
)项目一启动 会自动执行
as_view
方法CBV在路由上匹配 其实本质就是FBV 路由 >>>>视图函数内存地址
# CBV写法 url(r'^login/',views.MyLogin.as_view()), # url(r'^login/',views.view) # 访问属性和方法 # 方法就是函数(函数名加括号执行优先级最高) # 项目一启动 会自动执行as_view方法 # views.test和上面登录的views.view本质上写法是一样的,CBV在路由匹配上 其实本质还是FBV 路由 >>> 视图函数内存地址 url(r'^test/',views.test), url(r'^index/',views.index),#index在匹配上路由的时候触发 url(r'^login/',views.MyLogin.as_view()),#在浏览器上出入login就会触发 # 如果在urls中设置url(r'',home),会截获所有的url,如果放在文件的下面不截获 #网站首页可以使用url(r'^$',home) #访问网站404页面的设计 url(r'',error)
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs): #闭包函数
self = cls(**initkwargs) # cls是我们自己写的类 MyLogin self是我们自定义的类的对象
#在看源码的时候 你一定要把握住一个顺序 对象在查找属性和方法的时候
#先从对象自身找 再去产生对象的类中找 再去类的父类中找
return self.dispatch(request, *args, **kwargs)
return view #view返回的是内部函数的函数名
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
#判断当前请求方式在不在默认的八个方法内
======1.先以GET方法为例======
if request.method.lower() in self.http_method_names:
#利用反射去我们自定义类的对象中查找get属性或者是方法 getattr(obj,'get')
#handler = get方法
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 调用get方法
- 给CBV加装饰器
给CBV加装饰器 推荐使用内置模块
from django.utils.decorators import method_decorator
======2.可以指定给谁装======
#@method_decorator(outter,name='post')
#@method_decorator(outter,name='dispatch')
class MyLogin(View):
@method_decorator(outter)
def dispatch(self, request, *args, **kwargs): # 如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截
return super().dispatch(request,*args,**kwargs)
# @outter # 1.直接写
# @method_decorator(outter) # 1.推荐写法
def get(self,request):
print('我是MyLogin里面的get方法')
return render(request,'login.html')
# @outter
def post(self,request):
print('我是MyLogin里面的post方法')
time.sleep(1)
return HttpResponse('post')
模板层
-
模板语法
只有两种书写格式
{{}} 变量相关
{%%} 逻辑相关
-
模板传值
到底能传哪些数据类型
python基本数据类型全部支持传值
<p> 传函数名{{index}} 给html页面传递函数名的时候 模板语法会自动加括号调用函数 并且将函数的返回值当做展示依据 模板语法不支持函数传参 也就意味着 你传给html页面的只能是不需要传参调用的函数 </p> <p>传类名:{{MyClass}} </p> <p>{{ obj.get_self }}</p> <p>{{ obj.get_cls }}</p> <p>{{ obj.get_func }}</p> <p>只要是能够加括号调用的 传递到html页面上的都会自动的加货号调用</p1> 给html页面传值的两种方式 第一种 指名道姓 当需要传递的变量名特别多的情况下 有点麻烦 return render(request,'test.html',{'n':n}) 第二种 locals() 会将当前所在的名称空间中所有的名字 全部传递给html页面 return render(request,'test.html',locals())
-
过滤器
语法结构
模板语法也给你提供了一些的内置的方法 帮你快速的提供处理数据的能力
最多是两个参数
前端的取消转义
|false
后端
from django.utils.safestring import mark_safe
sss2 = "<h2>我的h2标签</h2>"
res = mark_safe(sss2)
<p> 模板语法之过滤器 会自动将|左边的数据当前过滤器的第一个参数 传入 :右边的当做第二个参数</p>
{<p>统计长度(如果无法统计默认返回0):{{s|length}}</p>}
{<p>加法运算(内部异常捕获 支持数字相加 字符串拼接 都不符合返回空):{{n|add:f}}</p>}
{<p>切片操作 顾头不顾尾 也支持步长 :{{l|slice:'0:5:3'}}</p>}
{<p>判断是否有值 (有值展示值的本身 没有值展示默认的值):{{ is_value|default:'is_value变量名指向的值为空' }}</p>}
{<p>自动转成文件大小的格式:{{file_size |filtesizeformat}}</p>}
{<p>截取文件的内容(字符) 截取五个字符 后面的三个点也算:{{ s|truncatechars:8 }}</p>}
{<p>截取文本的内容(按照空格计算) 截取五个单词 三个点不算:{{s1|truncatewords:5}}</p>}
{<p>默认情况下 是不会自动帮你转换成前端的html标签的 防止恶意攻击</p>}
{<p>展示带有标签的文本:{{sss|safe}}</p>}
{<p>展示带有标签的文本:{{sss1|safe}}</p>}
-
标签
逻辑相关的
if
for循环
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 %} <p>模板语法的取值 只有一种方式 统一采用点(.)的方式</p> <p>{{ comp_dic.hobby.2.2.age }}</p> 当你的数据是通过比较复杂的点点点获取到的后续又需要经常使用 你可以给该数据起别名 别名只能在with内部使用 {% with comp_dic.hoby.2.2.age as age %} <p>{{age}}</p> <p>{{ comp_dic.hoby.2.2.age}}</p> {% endwith%}
-
自定义过滤器和标签
django支持用户自定义
必须要先有三步准备
1.在应用名下新建一个名字必须是templatetags文件夹
2.在该文件夹内 新建一个任意名称的py文件
3.在该文件中 必须先写下面的两句代码
from django.template import Library
register = Library()
之后就可以利用register来自定义过滤器和标签
-
使用自定义的过滤器
需要先在html页面上 加载
自定义过滤器 跟默认的过滤器一样 最多只能接受两个参数
@register.filter(name='baby') def index(a,b) return a+b
自定义标签
自定义的标签可以接受任意多个参数
@register.simple_tag(name='mytag') def mytag(a,b,c,d): return '%s?%s?%s?%s?'%(a,b,c,d)
自定义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页面 {#<p>自定义过滤器的使用</p>#} {#{% load mytag %}#} {#{{ 1|baby:1 }}#} {#{{ 1|baby:100 }}#} 自定义标签的使用 可以接受多个参数 参数之间必须空格隔开 {#{% load mytag %}#} {#{% mytag 'a' 'b' 'c' 'd' %}#} {#{% load mytag %}#} 自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以 {#{% if mytag '1' '2' '3' '4' %}#} {# <p>有值</p>#} {# {% else %}#} {# <p>无值</p>#} {#{% endif %}#} 自定义inclusion_tag 的使用 当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag {% load mytag %} {% xxx 5 %} 标签 逻辑相关 索引:'counter0':0 计数:'counter':1 能够判断for循环的开始:'first':True 能够判断for循环的结束:'last':True
-
模板继承
你需要事先在你想要使用的页面上 划定区域 之后在继承的时候 你就可以使用你划定的区域
也就意味着 如果你不划定任何区域 那么你就将无法修改页面上的内容
{% block content %} {% endlock %} 先在页面上利用block划定你以后可能想改的区域 继承之后 就可以通过名字找到对应的区域进行修改 {% extends 'home.html'%} {% block content %} 修改模板中content区域内容 {% endblock %} 模板上的block区域越多 页面的扩展性越高 建议你一个模板页面至少有三块区域 css区域 html代码区域 可以设置多个block js区域 有了这三块区域 就能实现每一个页面都有自己独立的css和js代码 {% extends 'home.html' %} {% block css %} <style> p { color: green; } </style> {% endblock %} {% block content %} <p>login页面</p> {% endblock %} {% block js %} <script> alert('login') </script> {% endblock %} 你还可以在子页面上继续沿着父页面的内容 {{ block.super }} 模板的继承 先在你想要继承的页面上通过block划定你将要改动的区域 在子页面上先继承extends 利用block自动提示 选择你想要修改的内容的区域
-
模板导入
将html页面当做模块的直接导入使用
静态文件目录路径
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static')]