Django——多层,,CBV和FBV,, 执行流程__源码分析,,django模版修改的视图函数,,页面静态化,,内置过滤器,,绑定给类的方法
Django分了很多层
路由曾
视图层 请求对象和响应对象
模板曾
模型层:orm:表单,多表,各种查询
ajax forms组件 分页器 cookie session 中间件 auth
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————视图层响应对象
响应本质都是HttpReponse
HttpReponse---字符串
render-------放个模板 模板渲染是在后端完成的
js代码实在客户端浏览器里执行的
模板语法是在后端执行的
redirect---------重定向
-字符串参数部分是空的
状态码是 3开头 status=201
JsonResponse json格式数据
return JsonResponse({name:lqz,age:19})
本质是把传入的字典或列表(必须指定safe =False),使用 json序列化得到 json格式字符串----最终做成 HttpResponse返回给前端----- 如果想给 json序列化的时候,传参数,必须使用 json_dumps_params字典传入
如果想往响应头中写数据---需要传headers = {‘xx’:‘xx’}
JsonResponse源码分析
return JsonResponse({name:lqz,age:19}) 注:如果是列表 那么safe要改成 False 否则会抛异常
触发 JSonResponse的__init__ ----------{name:lqz,age:19} 给了data
def __init__(self, data, encoder=DjangoJSONEncoder,
safe=True,json_dumps_params=None, **kwargs):
如果传入的四字典
safe是True,后面是False,条件不符合,内部就不会走
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None: # 条件符合
json_dumps_params = {}
kwargs是字典---》setdefault--》有则修改,无则新增
kwargs.setdefault('content_type', 'application/json')
核心---》把字典转成json格式字符串,赋值给data
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__ 调用父类的 __init__ 完成实例化---》HttpResponse的对象
return HttpResponse(data,**kwargs)
super().__init__(content=data, **kwargs)
isinstance
isinstance(对象,类)判断这个对象,是不是这个类的对象
CBV和FBV
FBV:基于函数的视图
之前的都是FBV
CBV写法
from django.views import View
class UserView(View):
写方法---跟请求方式同名的方法
def get(self,request,*args,**kwargs)
必须返回四件套
路由配置:
path('index/', 视图类名.as_view()) as_view是类的绑定方法
执行流程--》源码分析
path('index/', index),--->请求来了,路由匹配成功会执行 index(request,)
path('index/', UserView.as_view()),
1 入口:路由---》as_view来开始
-请求来了,路由匹配成功---》执行---》UserView.as_view()(request)
-需要看as_view()执行结果是什么--》view--》代码如下
def view(request, *args, **kwargs): # 方法,可以加括号调用
return self.dispatch(request, *args, **kwargs)
-本质就是在执行 view(request)
-本质在执行---》self.dispatch(request, *args, **kwargs)
-去类(UserViwe类中找,找不到,去父类View)中找dispatch,代码如下
def dispatch(self, request, *args, **kwargs):
request当次请求的请求对象,取出请求方式【假设是get请求】,转成小写 'get'
http_method_names = ['get', 'post', 'put']
条件成立,执行if内部代码
if request.method.lower() in self.http_method_names:
getattr:反射---》通过字符串去对象中取属性或方法
self是谁的对象? 是View这个类的对象,这个是视图类UserView的对象
取出来的handler 是 UserView这个类的get方法
handler = getattr(self, 'get')
else:
handler = self.http_method_not_allowed
handler是 UserView这个类的get方法
get(request)---》触发UserView这个类的get方法---》真正执行原来视图函数的内容
最终返回
return handler(request, *args, **kwargs)
总结:写cbv,只需要在视图类中写跟请求方式同名的方法即可--》不同请求方式,就会执行不同的方法
关于类中self是谁的问题
class Animal:
def run(self):
这个self,是谁调用,就是谁
print(type(self))
print(self.name, '走路')
class Person(Animal):
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name,age):
self.name = name
self.age=age
p = Person('lqz')
p.run() #
dog=Dog('小奶狗',6)
dog.run()
self 是谁调用。self就是谁,不能只看是哪个类
上传文件
关于模板查找路径是配置文件中
TEMPLATES --->'DIRS': [os.path.join(BASE_DIR, 'templates')]
## python
class FileView(View):
def get(self,request):
return render(request,'file.html')
def post(self,request):
拿出文件对象
my_file=request.FILES.get('myfile')
print(type(my_file))
my_file=request.FILS.egt('myfile')
通过 print(type('my_file'))查看类型
#django.core.files.uploadedfile.InMemoryUploadedFile 跟之前用的文件对象不一样但是,它应该继承了文件
from django.core.files.uploadedfile import InMemoryUploadedFile
1 保存 2 取出文件名字
my_file.save() #找了一顿,没有,所以不能使用(save)快捷保存方式,需要自己写保存
print(my_file.name) 看neme属性是不是 这个文件的名字
3-xxxxx.md
自己写保存,放在项目根路径下
with open(my_file.name,'wb') as f:
for line in my_file:
f.write(line)
return HttpResponse('上传成功')
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" (默认当前地址)method="post" enctype="multipart/form-data"> --编码格式
<input type="file" name="myfile">
<br>
<input type="submit" value="提交"> 目前记得注掉 srf
</form>
</body>
</html>
此时点post提交 会报错
需要写 def post(self,request):
拿出文件
my_file=request.FILS.egt('myfile')
通过 print(type('my_file'))查看类型
模板 templease.html
模板在浏览器中运行不了,因为它有模板语法 浏览器解析不了模板语法
必须在后端渲染完成(替换完成) 变成纯粹的html,css,js
这种在后端会被渲染 类python语法 它叫模板语法 django中它又叫 dtl: django template language
django模板修改的视图函数
了解####
# ================================django模板修改的视图函数
from django.template import Template,Context
now=datetime.datetime.now()
# 内部打开了这个模板---》读出所有内容,实例化得到了t对象
t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
# #t=get_template('current_datetime.html')
c=Context({'current_date':str(now)})
html=t.render(c)
return HttpResponse(html)
另一种写法(推荐)
import datetime
now=datetime.datetime.now()
return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
# 总结:咱们之前这么写
render(request,'模板名字',context={key:value,key1:value})
本质是:
t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
c=Context({'current_date':str(now)})
html=t.render(c) # 返回是字符串
HttpResponse(html)
页面静态化#######
-把什么页面,做成静态化的?---》访问量高的页面
-目的:提高项目并发量,响应速度和效率就高了
-把首页静态化
def index(request):
# 1 判断 cache文件夹下有没有 index.html 纯静态页面
# 2 如果没有:干下面的事
# books = Book.object.all()
# t = Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
# # #t=get_template('current_datetime.html')
# c = Context({'books':books})
# html = t.render(c)
#保存到某个文件中 cache文件夹下 index.html
# 3 如果有那个文件,打开文件---》HttpReponse
books=Book.object.all()
return render(request,'index.html',{books:books})
模板语法###
变量:{{ 变量名 }} 字典,列表,对象 通过.拿到属性或方法
字典:dic.name--->这不是python语法 dic['name'] dic.get('name')
列表:list.2--->这不是python语法 list[0]
对象:person.name---->是python语法
person.run---->不是python语法,会自动加括号,把run的返回值放在模板中 person.run()
不支持传参数
1 深度查询 用句点符
2 过滤器
3 标签:{{% % }}
内置过滤器####
# render(request,'index.html',{now:当前时间对象})
{{ now | date:"Y-m-d H:i:s" }}
safe 把标签字符串 渲染成标签
'<a href=""></a>'--->渲染成标签
dtl是不存在xss攻击的?跨站脚本攻击
# 后端:
s='
<script>
alert(1)
</script>
'
render(request,'index.html',{s:s})
#模板
{{s}} 不会渲染成标签,没有xss攻击
我们知道s是安全的,我们可以使用safe标签,把它渲染成 真正的标签
模板导入 include ,写好一段前端代码块,以后别的页面要用,直接 {% include 'little.html' %}
#### little.html 这个是以后要导入的代码块
<div>
<h1>我是广告</h1>
<p>亚洲最大同性交友平台</p>
<p>名字是:{{ name }}---诚信交友</p>
</div>
#### 在index.html 或者 login.html中想用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
{% include 'little.html' %} # 这个位置引入即可,但是如果little中有模板语法,需要如下
</div>
<hr>
<div>
我是div222
</div>
</body>
</html>
### python代码:
def index(request):
return render(request, 'index.html', {'name': '彭于晏'})
-1 {{变量}} {{变量.取值}}
-2 {%for%}
-3 {%if%}
-5 内置过滤器 :data,length。。。
-6 include
-7 extends使用
————————————————————————————————————————————————————————————————————————————————————————————————
0 cbv执行流程,self问题(写代码试试) ---》整理到笔记中
cbv执行流程: 请求进入——进行路由匹配——如果匹配到对应的路由,内部就会执行XXXview.as_view()(request),因为XXXview中没有as_view()这个方法,所以去它的父类View中找,内部开始执行,View的as_view内部的view闭包函数,闭包函数执行了self.dispatch,这里的self是在XXXview类实例化的对象,在self.dispatch中通过反射找到同名的方法,然后执行,把request传入。
# 1 你自己写一个类,实现JsonResponse 功能,不需要传safe=False,无论字典或列表,都能完成序列化返回给前端
如果写在哪里都觉得不合适,那么新建一个py文件(名字随意) 在里面写一个 类 class MyResponse()那么他一定要继承一个类
要继承 HttpResponse,那么需要把这个 HttpResponse 导进来 (要从django中导过来)from django.shortcuts impor HttpResponse
注:肯定是不能继承 JsonResponse的 只用pass就行 ,所以我们要用 HttpResponse 逻辑重写 ——类加括号 会触发他的 __init__
但是你传了一个参数 就需要接收它 (简单的话 只需要判断它是不是列表参数或者字典参数,否则不能处理) 也可以
res=json dumps(data) return super( )_init_(res) 标红是绝对路径 去掉则是相对路径
而在视图函数中 views.py def index(request) 导入之前写的 from(app01).response import MyResponse
({‘code’:100,‘msg:' 提交成功’})
后 配路由 urls.py里
from app01.views import index
urlpatterns =[
path(‘admin/’),admin.site.urls},
path(‘ ’,index), 根路径不要加 /
]


# 2 四种情况,在响应头返回数据 xx=xx
四件套 导入

def index(request):
return HttpResponse(‘ok’,headers=‘xxxx’) 前端可以看到的 ok
也可以 obj=HttpResponse(‘ok’)
obj['???']='???' 像字典一样放入 最终会放到 Http的响应头中
print obj 但是这是个对象 但两者效果是是一样的

插曲:
--------------------------------------------------------------------
反向解析
# return redirect(‘ 第三方网址/自己的地址’)
# res=resolve_url(' login')
# return redirect(res) 通过名字拿到真正字符串地址——反向解析的作用 (在视图类,视图函数, 模板里)
---------------------------------------------------------------------------------------------------
————redirect 重定向
def index(request)
return redirect(‘ /login’,heraders={‘xxx’:‘xxxx’}) 一访问 会重定向地址 需要往里放东西 而他的源代码里 有 **kwargs 参数
urls: path(‘login/’,login,name=‘login’)
views : def login (request):
return HttpResponse(‘login’) 访问首页跳到页面 访问头 没有 说明不生效 ,这时 需要用到上面的OBJ
obj=redirect=(‘/login’)
obj['xxx']='xxx'
return obj 这时访问头 有数据
————render
return render(request,‘ index.html’,headers={''xxx'='xxx')
建一个 html 不需要填写 直接跳转后 发现不能接受 hearders 只能再用 OBJ
obj=render(request,‘index.html’)
obj[xxx']='xxx'
return obj 此时可以访问
————JsonResponse
return JsonResponse({‘name’:‘sdsd’}),headers={‘xxx’:‘xxxxx’} 有提示 所以 当有提示的时候 此方法可行
obj =JsonResponse({‘name’:‘xxxx’})
obj=['xxx']='xxx'
return obj 发现也可以访问 因此我们得出 obj四个都可以使用,而 headers方法 不具有通用性
# 3 绑定给类的方法,类来调用,对象可以调用吗?如何用
绑定给对象的方法,对象来调用,类可以来调用吗?如何用
class Person:
# 对象绑定方法---》写在类中,没有任何装饰器
def run(self):
print(self.name)
print('人走路')
类来调用对象的绑定方法---》这个方法就变成了普通函数,有几个值就要传几个值
正常需要传这个类的对象---》因为可能方法内部使用了对象
但是如果内部没有使用对象---》可以随意传个对象
Person.run(Person( )) 但是取name时 是因为 Person 对象没有 name属性
———— 类的绑定办法 必须要用 classmethon修饰
@classmethond
def xx(cls): [括号内是形参,具体需要看调用传的是谁]
把类传入,类可以实例化得到对象 ——cls() 但是里面如果写了__init__ 会报错 因为cls()=Person()
p=cls() 直接类实例化得到对象 要不要传参数 取决于 Person类有没有写 _init_
print(p) ------内存地址
print(‘ 类的绑定方法.xxx’)
绑定给类的方法
Person.xx() 就是将自己本身传进去
p=Person()
p.xx() 对象来调用类的绑定方法实际是 将当前对象的类传递进去
类中还有 静态方法 [虽然叫静态方法 但是本质 是个函数]
@staticmethod
def yy():
print(‘staticmethod’)
Person.yy() [类来调用]
Person().yy() [对象来调用] 二者是不一样的
总结:函数和方法
方法有特殊性,绑定给谁,就需要谁来调用,调用时会自动传值---》只能能自动传值,它就是个方法
# 函数,有几个值就要传几个值,不能多也不能少
# 5 写个图片上传功能,图片保存在根路径media文件夹下,上传成功直接在前端显示出上传的图片
-开启media的访问
创建一个media文件
views: def upload_ing(request):
myfile=request.FILES.get(' myfile')
with open("/media%s"%myfile.name,'wb' ) as f:
for line in myfile:
f.write(line)
return HttpResponse('图片上传成功') 缺少前端form表单 写或者用postman
urls: path(‘upload_imgg/’,upload_img), 启用路径 发POST请求
注掉 srf 后会发现 没有文件夹 的路径
可在 setting中 MEDIA_ROOT=os.path.join(BASE_DIR,'media') 而此时 需要修改views 导入路径
而 from.django.conf import setting 和from_dem04 import setting 二者 前者是系统内置 缺少的会内补 后者是自己配置 缺少会报错
print(settings.MEDIA_ROOT)
with open("/media%s"%myfile.name,'wb' ) as f: 改为 with open(settings.MEDIA_ROOT+'/%S' % myfile.name,'wb')as f:
访问不到的原因 是路径 需要将其开启
而static文件夹 配置文件写好会自动开启 假如static文件里有个图片 ,不能直接 http://127.0.0.1:8000/static/img/default.png
配置文件没有配
STATIC_URL =‘/static/’
STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')] 注:static文件下不要放重要内容
想让media这个文件夹像static文件夹一样,能被用户浏览器访问---》自己开启路由-->url中写路由
from django.views.static imoprt serve
from django.conf import settings
访问的路径是:http://127.0.0.1:8000/ media/default.png
-正则方法 re_path
re_path('^media/(?P<path>.*)', serve, kwargs={'document_root': settings.MEDIA_ROOT}),
media/ img/default.png
访问meida这种路径,django会去 document_root指定的文件夹下找对应的文件
-转换器 path
path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT})
3 以后想开启media的访问
1 在项目根路径创建media文件
2 在配置文件中配置
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
3 路由中配置:path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT})
'''
return HttpResponse('图片上传成功')
# 6 建个表---》插入100条数据---》写个页面,for循环把100条数据显示在页面上
-只要用户访问---》就会去查
-做成静态化
models.py
form django.import models
class
Book(models.Modexl):
name=models.CharField(max_length=32)
price =models.IntergerField()
publish=models.CharField(max_length=64)
迁移数据库 ——Run manage.py Task makemigration megritae
from.models import Book
from .models import Book
from django.conf import settings
from django.template import Template, Context
def books_view(request) 页面展示图书 先查看所有书
做静态化
if os.path.exists(os.path.join(settings.BASE_DIR, 'cache', 'books.html')):
print('不走数据库')
with open('cache/books.html', 'rt', encoding='utf-8') as f:
res_str = f.read()
return HttpResponse(res_str)
else:
books = Book.objects.all()
with open('templates/books.html', 'rt', encoding='utf-8') as f:
res = f.read()
t = Template(res)
c = Context({'books': books})
html = t.render(c)
# 保存起来
with open('cache/books.html', 'wt', encoding='utf-8') as f:
f.write(html)
return HttpResponse(html)
渲染模板 return render(request,‘books.html’,{‘books’:book})
--books.html
————bookstore copy
div?》


# 7 (能做就做)自定义一个过滤器---》实现
数据有个表---》content字段---》别人存入了一些敏感词
它**
高级一些:关键词放到一个列表中,可以随时增加,不需要重启项目---》数据可以放在数据库中
浙公网安备 33010602011771号