day54

今日内容

视图层

​ 小白必会三板斧
​ 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不自动帮你对中文进行转码
# 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能够根据请求方式的不同 自动执行不同的方法???

访问属性和方法
方法就是函数(函数名加括号执行优先级最高)
项目一启动 会自动执行as_view方法

参考截图
@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

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方法

模板层

​ 模板语法
​ 只有两种书写格式
​ {{}} 变量相关
​ {%%} 逻辑相关

模板传值
到底能传哪些数据类型

python基本数据类型全部支持传值

传函数名:{{ index1 }} 给HTML页面传递函数名的时候 模板语法会自动加括号调用该函数 并且将函数的返回值当做展示依据 模板语法不支持函数传参 也就意味着 你传给html页面的只能是不需要传参调用的函数

传类名:{{ MyClass }} 自动加括号实例化产生对象

传对象:{{ obj }}

{{ obj.get_self }}

{{ obj.get_cls }}

{{ obj.get_func }}

总结:只要是能够加括号调用的 传递到html页面上都会自动加括号调用

过滤器 语法结构: | 模板语法也给你提供了一些内置的方法 帮你快速的处理数据

最多只能有两个参数

前后端取消转义
前端
|safe
后端
from django.utils.safestring import mark_safe
sss2 = "

我的h2标签

"
res = mark_safe(sss2)

模板语法之过滤器 会自动将|左边的数据当前过滤器的第一个参数传入 :右边的当做第二个参数

{#

统计长度(如果无法统计默认返回0):{{ s|length }}

#} {#

加法运算(内部异常捕获 支持数字相加 字符串拼接 都不符合返回空):{{ n|add:f }}

#} {#

切片操作 顾头不顾尾 也支持步长:{{ l|slice:'0:5:2' }}

#} {#

判断是否有值(有值展示值本身 没值展示默认值):{{ is_value|default:'is_value变量名指向的值为空' }}

#} {#

自动转成文件大小格式:{{ file_size|filesizeformat }}

#} {#

截取文本内容(字符) 截取五个字符 三个点也算:{{ s|truncatechars:8 }}

#} {#

截取文本内容(按照空格计算) 截取五个单词 三个点不算 :{{ s1|truncatewords:5 }}

#} {#

默认情况下 是不会自动帮你转换成前端html标签 防止恶意攻击

#} {#

展示带有标签的文本:{{ sss|safe }}

#} {#

展示带有标签的文本:{{ sss1|safe }}

#}

标签 逻辑相关
if
for循环

for if联合使用
{% for foo in l %}
{% if forloop.first %}

这是我的第一次


{% elif forloop.last %}

这是最后一次了啊


{% else %}

{{ foo }}


{% endif %}
{% empty %}

当for循环的对象是空的时候会走

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

{{ comp_dic.hobby.2.2.age }}

自定义过滤器和标签
django支持用户自定义
必须要先有三部准备
1.在应用名下新建一个名字必须叫templatetags的文件夹
2.在该文件夹内 新建一个任意名称的py文件
3.在该py文件中 必须先写下面两句代码
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页面

{#

自定义过滤器的使用

#}
{#{% load mytag %}#}
{#{{ 1|baby:1 }}#}

{#

自定义标签的使用 可以接受多个参数 参数与参数之间必须空格隔开

#}
{#{% load mytag %}#}
{#{% mytag 'a' 'b' 'c' 'd' %}#}
{#{% load mytag %}#}
{##}
{#

自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以

#}
{#{% if mytag '1' '2' '3' '4' %}#}
{#

有值

#}
{# {% else %}#}
{#

无值

#}

自定义inclusion_tag的使用 当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag

{% load mytag %} {% xxx 5 %}

模板的继承
你需要事先在你想要使用的页面上 划定区域 之后在继承的时候 你就可以使用你划定的区域
也就意味着 如果你不划定任何区域 那么你将无法修改页面内容

{% block content %}
{% endblock %}
先在页面上利用block划定你以后可能想改的区域

继承之后 就可以通过名字找到对应的区域进行修改

{% block content %}
修改模板中content区域内容

模板上的block区域越多 页面的扩展性越强
建议你一个模板页面至少有三块区域
css区域

html代码区域 可以设置多个block

js区域

有了这三块区域 就能够实现每一个页面都有自己独立的css和js代码

{% extends 'home.html' %}

{% block css %}

{% block content %}

login页面

{% endblock %}

{% block js %}

你还可以在子页面上继续沿用父页面的内容

模板的继承
1.先在你想要继承的页面上通过block划定你将来可能要改的区域
2.在子页面上先继承extends
3.利用block自动提示 选择你想要修改的内容区域

模板的导入
将html页面当做模块的直接导入使用

{% include 'bform.html' %}

昨日内容回顾

​ 表关系的建立方式
​ 表与表之间的关系就三种
​ 一对一 OneToOne(to='') # to后面可以跟字符串的表名 也可以直接跟变量名表名(该表名必须在上面提前定义出来)
​ 一对多 ForeignKey(to='')
​ 多对多 ManyToMany(to='')
​ 自己一定要会三种关系的推导步骤 以及建表的注意事项

一对一和多对多外键字段 建在哪一方都可以 但是推荐你建在查询频率较高的一方 以便后续的orm查询
一对多外键字段 建在多的那一方

一对一和一对多外键字段 在创建表的时候回自动加_id后缀 无论你有没有加

多对多字段不会在表中创建出来 只是用来告诉orm自动帮你创建第三张表
能够方便后续orm查询操作

django请求生命周期流程图

路由层
url方法第一个参数是一个正则表达式
匹配的特点:只要正则表达式能够匹配到内容 那么会立刻结束匹配 直接执行后面所对应的视图函数
正是由于该特点会出现,当你的项目特别庞大的时候 可能会出现url被顶替的现象(test testadd)
如果出现上述情况
1.修改正则表达式
2.将下面的放到上面去

django在路由匹配的时候默认有一个补救机制
当你的url没有正常匹配到 django会让浏览器自动加斜杠再来匹配一次(重定向)
配置文件中有一个参数用来控制该机制是否允许
APPEND_SLASH = True/False

网站首页可以使用的匹配方式
网站首页
url(r'^$',home),
网站404页面的设计(了解)
url(r'',error)

路由匹配

无名分组
给正则表达式加括号分组 在路由匹配成功之后调用视图函数的时候
会将括号内正则表达式匹配到的内容当做位置参数传递给视图函数
url(r'^index/(\d+)/',index) # index(request,\d+内容)

有名分组
给正则表达式加括号分组并起别名 在路由匹配成功之后调用视图函数的时候
会将括号内正则表达式匹配到的内容当做关键字传递给视图函数
url(r'^index/(?P\d+)/',index) # index(request,year=\d+内容)

注意事项 无名有名不能混合
但是单个情况下 可以使用多次

反向解析
本质:根据别名 动态解析出一个结果 该结果可以直接访问到别名所对应的url
没有正则表达式符号
url(r'^index/',views.index,name='xxx')

前端
{% url 'xxx' %} # index/
后端
from django.shortcuts import reverse
reverse('xxx') # index/

出现正则表达式符号
# 无名分组
url(r'^index/(\d+)/',views.login,name='yyy')
# index/数字/
前端
{% url 'yyy' 数字 %} # index/数字/
后端
reverse('xxx',args=(数字,))
# 只要是容器类型 内部就算只有一个元素 你也给我习惯性的把分隔符逗号加上

有名分组
# 你可以直接使用无名分组的方式即可
​ 前端
​ {% url 'yyy' 名字=数字 %} # index/数字/
后端
​ reverse('xxx',keargs={'名字':数字})

路由分发
前提
所有的app都可以有自己独立的urls.py templates模板文件夹 static静态文件夹
正是由于该特点 使得基于django实现多人开发 非常的方便
每个人只需要开发自己的app即可

路由分发
总路由不再直接做路由与视图函数对应关系了
而是仅仅做一个转发的功能
好处:更加的解耦合 更加好维护
from django.conf.urls import url,include

url(r'^应用名1/',include('应用名1.urls'))
url(r'^应用名2/',include('应用名2.urls'))

名称空间
当不同的应用中给路由与视图对应关系起了相同的别名
在反向解析的时候 并不能直接识别到是哪个应用下的
url(r'^应用名1/',include('应用名1.urls',namespace='应用名'))

{% url '应用名1:相同的别名' %}

reverse('应用名1:相同的别名')
reverse('应用名2:相同的别名')

其实你完全可以不适用名称空间
你只需要保证在起别名的时候不要出现冲突即可 建议做法就是加 应用前缀_别名

虚拟环境
给每一个项目提供一个专门属于该项目自己的所需模块
避免浪费 节省资源
requirement.txt
django1.11.11
Flask
1.4
建议不要频繁的开设虚拟环境

django版本区别
path与url
path第一个参数不支持正则 如果你还想使用正则 你可以re_path跟你的url一模一样

path虽然不支持正则 但是提供了五个默认的转换器 能够自动帮你转换数据类型

还支持用户自定义转换器(不要记忆 直接拷贝即可)

request方法获取文件数据
request.FILES 获取form表单上传的文件数据

file_obj = request.FILES.get('myfile')
file_obj.name 文件名

f = open(file.obj.name,'wb')
for chunk in file_obj.chunks(): # for line in file_obj:
f.write(chunk)
f.close()

posted @ 2019-11-26 22:11  lucky_陈  阅读(108)  评论(0)    收藏  举报