视图层
- 
小白必会三板斧 - HTTPresponse 返回字符串
- render 返回给html页面传值
- redirect 重定向
 
- 
视图函数必须有一个返回值 并且返回值的数据类型必须是HTTPresponse对象 
- 
render 利用Template,Context这两个模块推导 
def login(request):
    res=Template('<h1>{{user}}</h1>')
    con=Context({'user':{'username':'jason','password':'123'}})
    return HttpResponse(res.render(con))
返回的页面是这个大字典
- JsonResponse
- 前后端分离
- 前后端数据交互 该如何进行?
- 通常情况下前后端数据交互采用的都是json字符串(字典),后端只需要写好相应的url接口,前端访问该接口,你只需要返回一个大字典即可+开发文档,用来告诉前端工程师 这个接口能够返回哪些数据
 
- 前后端序列化反序列化都用哪些方法
- Python后端:json.dumps json.loads
- js:JSON.stringify JSON.parse
 
 
写法一:
#该视图函数需要返回一个json格式的字符串
from django.http import JsonResponse
def index(request):
    user_dic={'name':'you are最棒的 加油哦~','password':'123'}
    #如何让json不自动把中文转码
    json_str=json.dumps(user_dic,ensure_ascii=False)
    return HttpResponse(json_str)
写法二:
from django.http import JsonResponse
def index(request):
    user_dic={'name':'you are最棒的 加油哦~','password':'123'}
    return JsonResponse(user_dic,json_dumps_params={'ensure_ascii':False})
为了允许一个非字典对象被序列化,需要给一个safe参数,并把safe设置成false
from django.http import JsonResponse
def index(request):
    l=[1,2,3,4,5]
    return JsonResponse(l,safe=False)
#JsonResponse默认序列化字典用的,如果想序列化其他数据类型(json模块可以序列化的),需要加一个safe参数
- 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')
    
路由的书写
    #FBV写法 路由>>>视图函数内存地址
    url(r'^index/',views.index),
    #CBV写法
    url(r'^login/',views.MyLogin.as_view())
- 
CBV的源码 - 思考:为什么CBV能够根据请求方式的不同 自动执行不同的方法
- 访问属性和方法
- 方法就是函数(函数名加括号执行优先级最高)
- 项目一启动 会自动执行as_view 方法
 
 url(r'^login/',views.view) #CBV在路由匹配上 本质还是FBV 路由>>>视图函数内存地址@classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): # 闭包函数 self = cls(**initkwargs) # cls是我们自己写的类 MyLogin self是我们自己定义的类的对象 # 在看源码的时候 你一定要把握住一个顺序 对象在查找属性和方法的时候 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get # 先从对象自身找 再去产生对象的类中找 再去类的父类中找 return self.dispatch(request, *args, **kwargs) #view函数返回什么 用户就能看到什么 return viewdef 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. #判断当前请求方式在不在默认的八个方法内 #先以GET请求为例 if request.method.lower() in self.http_method_names: #利用反射去我们自己定义类的对象中查找get属性或者方法 getattr(obj,'get') #handle=get方法 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed #这一步是调用get方法 return handler(request, *args, **kwargs) http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']- 给CBV加装饰器 推荐使用内置模板
 
- 思考:为什么CBV能够根据请求方式的不同 自动执行不同的方法
from django.utils.decorators import method_decorator
@method_decorator(outter,name='get') #可以指定给谁装
@method_decorator(outter,name='dispatch')
class MyLogin(View):
    @method_decorator(outter)
    #如果你想在视图函数执行之前 做一些操作 你可以在CBV中定义dispatch方法来拦截
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    @outter  #直接写
    @method_decorator(outter) #推荐写法
    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 }}</p>
			<p>{{ obj.get_self }}</p>
			<p>{{ obj.get_cls }}</p>
			<p>{{ obj.get_func }}</p>
只要能够加括号调用的 传递到html页面上都会自动加括号调用
- 过滤器 语法结构:|
- 模板语法也给你提供了一些内置的方法 帮你快速的处理数据
- 最多只能有两个参数
- 前后端取消转义
 
<p>模板语法之过滤器 hi自动将|左边的数据当做过滤器的第一个参数传入:右边的当做第二个参数</p>
<p>统计长度 (如果无法统计默认返回0):{{ s|length }}</p>
<p>加法运算(内部异常捕获 支持数字相加 字符串拼接 都不符和返回空):{{ n|add:f }}</p>
<p>切片操作 顾头不顾尾 也支持步长:{{ 1|slice:'0:5:2' }}</p>
<p>判断是否有值 (有值展示本身 没值展示默认值):{{ is_value |default:'is_value变量名指向的值' }}</p>
<p>自动转成文件大小格式:{{ file_size|filesizeformat }}</p>
<p>截取文本内容(字符) 截取五个字符 三个点也算:{{ s|truncatechars:8 }}</p>
<p>截取文本内容(按照空格截)截取五个单词 三个点不算:{{ s1|truncatewords:5 }}</p>
<p>默认情况下不会自动帮你转换成前端html标签 防止恶意攻击</p>
<p>展示带有标签的文本:{{ sss|safe }}</p>
<p>展示带有标签的文本:{{ sss1|safe }}</p>
<p>{{ res }}</p>
前端
   |safe
    
<p>标签 逻辑相关</p>
{% for foo in l %}
     <p>{{ forloop }}</p>
{% endfor %}
{% if s %}
<p>s有值</p>
{% else %}
<p>s没值</p>
{% endif %}
{% for foo in l %}
    {% 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>
<p>{{ comp_dic.hobby.2.2.age }}</p>
<p>当你的数据是通过比较复杂的点点点获取到的后续又需要经常使用 你可以给该数据起别名 别名只能在with内部使用</p>
{% with comp_dic.hobby.2.2.age as age  %}
    <p>{{ age }}</p>
    <p>{{ comp_dic.hobby.2.2.age }}</p>
{% endwith %}
后端
   from django.utils.safestring import mark_safe
   sss2="<h2>h2标签</h2>"
   res=mark_safe(sss2)
- 自定义过滤器和标签
- django支持用户自定义
- 必须要有三部准备
- 在应用名下新建一个名字必须叫templatetages的文件夹
- 在该文件夹内 新建一个任意名称的py文件
- 在该py文件中 必须先写下面两句代码
 
 
from django.template import Library
register=Library()
#之后就可以利用register来自定义过滤器和标签
- 
使用自定义的过滤器 #py文件中 #自定义过滤器 跟默认的过滤器一样 最多只能接受两个参数 @register.filter(name='baby') def index(a,b): return a+b #html文件中 <p>自定义过滤器的使用</p> {% load mytag %} {{ 1|baby:1 }} {{ 1|baby:100 }}- 需要先在html页面上 加载
 
- 
自定义的标签 
#自定义标签 可以接受任意多个参数
@register.simple_tag(name='mytag')
def mytag(a,b,c,d):
    return '%s?%s%s?%s'%(a,b,c,d)
<p>自定义标签的使用 可以接受多个参数 参数之间必须空格隔开</p>
{% load mytag %}
{% mytag 'a' 'b' 'c' 'd' %}
{% load mytag %}
- 自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以
{% if 1|baby:2 %}
    <p>有值</p>
    {% else %}
    <p>无值</p>
{% endif %}
- 自定义inclusion_tag:
- 是一个函数 能够接受外界传入的参数 然后传递给一个html页面页面上获取数据 渲染 完成之后将渲染好的页面 放到调用inclusion_tag的地方
 
mytag.py
@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页面
test前端展示页面.html
<p>自定义inclusion_tag的使用 当你需要一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 可以使用inclusion_tag</p>
{% load mytag %}
{% xxx 5 %}
mytag.html
<ul>
    {% for foo in l %}
    <li>{{ foo }}</li>
    {% endfor %}
</ul>
模板的继承
- 你需要事先在你想要使用的页面上 划定区域 之后在继承的时候 就可以使用划定好的区域 所以如果不划定任何区域 将无法修改页面内容
		{% block content %}
        {% endblock %}
		先在页面上利用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 %}
还可以在子页面上继续沿用父页面的内容
{{ bolck super }}
- 先在你想要继承的页面上通过block划定你将来可能要改的区域
- 在子页面上先继承extends
- 利用block自动提示 选择你想要修改的内容区域
模板的导入
将html页面当做模块的直接导入使用
{% include 'bform.html' %}   
 
                    
                     
                    
                 
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号