网页伪静态、视图层、模板层、form表单如何携带数据文件
网页伪静态
1.什么是伪静态网页?
伪静态是相对于静态文件来说的,例如https://www.cnblogs.com/hesujian/p/11165818.html
将一个动态网页伪装成静态网页
将url地址模拟成html结尾的样子,看上去像是一个静态文件,只是改变了URL的表现形式,实际上还是动态页面
搜索优化:seo
在路由的最后加上.html
2.伪静态的好处
1、美观(传统的问号拼接看起来比较杂乱)
2、seo(搜索引擎优化技术),搜索引擎比较喜欢收录静态页面,所以大家都做成伪静态去增加收录机会,增大本网站的seo查询力度,增加搜索引擎收藏本网站的概率
3.实现伪静态网页
# 在路由后面加上.html就可实现静态页面效果
path('index.html',view.index)
视图层
Django视图层,视图就是Django项目下的views.py文件,它的内部是一系列的函数或者是类,用来专门处理客户端访问请求后处理请求并且返回相应的数据,相当于一个中央情报处理系统。
1.三板斧
"""
HttpResponse
返回字符串类型
httpresponse() 括号内直接跟一个具体的字符串作为响应体,比较直接简单,所有这里主要介绍后面两种形式。
render
返回html页面 并且在返回给浏览器之前还可以给html文件传值
render(request, template_name[, context])结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
# 参数:
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
redirect
传递要重定向的一个硬编码的URL
def my_view(request):
rerurn redirect('/some/url/')
也可以是一个完整的URL
def my_view(request):
...
return redirect('http://www.baidu.com/')
"""
2.三板斧的本质
视图app01没有返回一个HttpResponse对象,返回一个None代替了
Django视图层函数必须要返回一个HttpResponse对象
django视图层函数必须有一个返回值,并且返回值的数据类型必须是HttpResponse对象
研究底层源码
1.def index(request):
return HttpResponse()
"""
按住ctrl点击进入HttpResponse:
发现HttpResponse其实是一个类,那么类名加()实例化产生一个对象
class HttpResponse(HttpResponseBase):
pass
"""
2.def index(request):
return render()
"""
按住ctrl点击进入render:
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
先执行的是render函数,然后render函数返回的是HttpResponse(content, content_type, status)
"""
3.def index(request):
return redirect()
"""
按住ctrl点击进入redirect:
def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))
按住ctrl点击进入HttpResponsePermanentRedirect:
class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
pass
按住ctrl点击进入HttpResponseRedirectBase:
class HttpResponseRedirectBase(HttpResponse):
pass
会发现它继承的也是HttpResponse
按住ctrl点击进入HttpResponseRedirect:
class HttpResponseRedirect(HttpResponseRedirectBase):
pass
按住ctrl点击进入HttpResponseRedirectBase:
class HttpResponseRedirectBase(HttpResponse):
pass
会发现它继承的也是HttpResponse
"""
'''综上研究发现:Django视图层函数必须要返回一个HttpResponse对象'''
3.视图函数返回json格式数据
def index(request):
# 将后端字典序列化发送到前端
user_dict = {'name': 'jason', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# 先转成json格式字符串
json_str = json.dumps(user_dict)
# 将该字段返回
return HttpResponse(json_str)
解决这个中文输入的问题我们之前是加了ensure_ascill=False,ensure_ascii 内部默认True自动转码,改为False不转码,只生成json格式,双引号
以上实现返沪json格式数据比较麻烦,又得转换json格式又得编码设置,那么Django的出现就在这方面做出了改变
JsonResponse
# 导入JsonResponse模块
from django.http import JsonResponse
def index(request):
user_dict = {'name': 'jason老师', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# json_str = json.dumps(user_dict, ensure_ascii=False)
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii':False}) # 直接写入JsonResponse,不需要去做json序列化操作
# user_dict,json_dumps_params={'ensure_ascii':False} :解决前端中文转码问题
JsonResponse底层
# 继承了HttpResponse,返回的还是HttpResponse对象
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
# json_dumps_params=None,注意这个参数,是一个默认参数
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=None,
json_dumps_params = {}
# 如果我们在这里传入了一个值,那么这里的json_dumps_params = {'XXX':'XXX'},然后在下面的data里面转换为的是关键字参数,XXX=XX
kwargs.setdefault('content_type', 'application/json')
'''
将data数据进行了json序列化,然后做了一个返回
**json_dumps_param,**加在字典前面,现在是在调用一个函数,那么它在这里做实参,**在是实参中将字典打散为关键字参数形式,就是什么等于什么
'''
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)
JsonResponse序列化(列表注意事项)
# 导入JsonResponse模块
from django.http import JsonResponse
def ab_json(request):
l = [111,222,333,444,555]
# 默认只能序列化字典 序列化其他需要加safe参数 safe=False
return JsonResponse(l,safe=False)
json与pickle区别
import json
'''支持的数据类型:str,list, tuple, dict, set'''
# 序列化出来的数据是可以看得懂的,就是一个字符串
dumps 将Python对象转换成json字符串
loads
dump 将Python对象写入json文件
load
import pickle
'''支持的数据类型:python中的所有数据类型'''
# 序列化出来的结果看不懂,因为结果是一个二进制
# pickle序列化出的来的数据只能在python中使用
dumps
loads
dump
load
4.FBV与CBV
1.FBV与CBV区别
FBV基于函数的视图(Function base view) 我们前面写的视图函数都是FBV
CBV基于类的视图(Class base view)
视图文件种除了用一系列的函数来对应处理客户端请求的数据逻辑外,还可以通过定义类来处理相应的逻辑。
# 视图函数既可以是函数也可以是类
def index(request):
return HttpResponse('index')
2.CBV
从index页面,后台修改action的参数,朝func发送post请求
点击提交以后自动出发了类里面的post方法
CBV比起FBV来说的话,不需要通过request.method来判断当前是什么请求,CBV会自动判断,是哪种请求,就去触发哪种方法(写在类里面里的函数叫做方法)
3.CBV底层源码
源码分析入口
path('func/', views.MyView.as_view())
"""
# 面向对象属性方法查找顺序
1.先从对象自己名称空间找
2.在去产生类对象的类里面找
3.在去父类里面找
"""
1.绑定给类的as_view方法(它是我们自己写的类里面继承的类)
class View:
@classonlymethod
def as_view(...):
绑定给类的,类调用会自动将类当作第一个参数传入
def view(...):
pass
return view
2.CBV路由匹配本质:跟FBV是一致的
path('func/', views.view)
3.访问func触发view执行
def view(...):
obj = cls() # 我们自己写的类加括号产生的对象
return obj.dispatch()
'''涉及到对象点名字 一定要确定对象是谁 再确定查找顺序'''
4.研究dispatch方法
def dispatch(...):
判断 request.method将当前请求方式转成小写 在不在 self内 self==MyLogin
"http_method_names 内有八个请求方式 合法"
['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
if request.method.lower() in self.http_method_names:
# getattr 反射: 通过字符串来操作对象的属性或者方法
func_name = getattr(obj,request.method.lower())
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
用到了一个反射的知识,从obj这个对象里面,找一个request.method.lower()这个的函数
form表单如何携带数据文件
form表单如何携带数据文件需要注意满足以下俩个要求
1.method属性值必须是post
2.enctype属性值必须是multipart/form-data
后端获取文件数据的操作,request对象方法
1.获取请求方式POST/GET
request.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
2.request.POST
获取POST请求提交普通的键值对数据 一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成
3.获取GET请求
request.GET
获取GET请求 一个类似于字典的对象,包含 HTTP GET 的所有参数
4.获取文件
request.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
5.原生的浏览器发过来的二进制数据
request.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,
例如:二进制图片、XML,Json等。
6.拿到路由
request.path
print(request.path) # /app01/index/
个字符串,表示请求的路径组件(不含域名)
7.拿到路由
request.path_info
print(request.path_info) # /app01/index/
8.能过获取完整的url及问号后面的参数
request.get_full_path()
print(request.get_full_path()) # /app01/index/?username=jason
实际案例展示
import json
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
# Create your views here.
def index(request):
# user_dict = {'name': 'jason老师', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# # json_str = json.dumps(user_dict, ensure_ascii=False)
# return JsonResponse(user_dict, json_dumps_params={'ensure_ascii':False}) # 直接写入JsonResponse,不需要去做json序列化操作
#
# # user_dict,json_dumps_params={'ensure_ascii':False} :解决前端中文转码问题
if request.method == 'POST':
# 普通的键值对形式的数据
print(request.POST)
# 专门用来携带过来的文件数据,流式的文件数据
print(request.FILES) # <MultiValueDict: {'file': [<InMemoryUploadedFile: 今日内容.md (application/octet-stream)>]}>
# 也可以取到这个文件,注意它也是一个Dict,可以通过点的方式得到,'file'由前端的name标签决定
file_obj = request.FILES.get('file')
# 可以使用这个对象去点出一些方法
print(file_obj.name)
# 也可以将这个文件保存下来,这个文件可以是文本文件,也可以是音频文件,只不过pycharm不能拿播放音频文件
with open(file_obj.name, 'wb') as f:
for line in file_obj:
f.write(line)
return render(request, 'index.html')
模板层
1.模板语法的传值
方式一:指名道姓的传
urls代码:
path('modal/', views.modal)
views代码:
def modal(request):
name = 'jason'
return render(request, 'modal.html', {'name':name})
指名道姓传参 不浪费资源
方式二:关键字locals()
html代码:
<body>
{{ name }}
{{ age }}
{{ gender }}
</body>
urls代码:
path('modal/', views.modal)
views代码:
def modal(request):
name = 'jason'
age = 18
gender = 'female'
return render(request, 'modal.html', locals()) # 将函数体里局部空间里所有的名字全部传入给前面的那个页面
将整个局部名称空间中的名字去全部传入简单快捷
2.模板语法传值的范围
基本数据类型直接传递使用
views代码
def modal(request):
i = 123
f = 13.4
s = 'study work hard'
d = {'name': 'Tony', 'pwd': 123}
t = (11, 22, 33)
se = {11, 22, 33}
b = True
return render(request, 'modal.html', locals())
html代码
<body>
<p>{{ i }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>
</body>
函数名的传递会自动加括号执行并将返回值展示到页面上,注意函数如果有参数则不会执行也不会展示 模板语法不支持有参函数
views代码
def modal(request):
def func1():
print('函数')
return '这里才能传过去值哦'
return render(request, 'modal.html', locals())
html代码
<body>
{#传递函数名会自动加括号调用 但是模板语法不支持给函数传额外的参数#}
<p>{{ func1 }}</p>
</body>
类名的传递也会自动加括号产生对象并展示到页面上,对象的传递则直接使用即可,对象默认情况下不可以加括号了,除非自己写__call__方法,模板语法会判断每一个名字是否可调用 如果可以则调用!!!
views代码
class MyClass(object):
def get_obj(self):
return 'obj'
@classmethod
def get_cls(cls):
return 'cls'
@staticmethod
def get_func():
return 'func'
obj = MyClass()'
return render(request, 'modal.html', locals())
html代码
<body>
{#传类名的时候也会自动加括号调用(实列化) 生成对象#}
<p>{{ MyClass }}</p>
{#内部能够自动判断出当前的变量名是否可以加括号调用 如果可以就会自动执行 针对的是函数名和类名#}
<p>{{ obj }}</p>
{#模板语法支持对象调用类方法#}
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_class }}</p>
</body>
django的模板语法在操作容器类型的时候只允许使用句点符,既可以点键,也可以点索引
.key
.index
.key.index.index.key
3.模板语法过滤器(类似于python内置函数)
1.模板语法过滤器
过滤器就类似于是模板语法内置的 内置方法
模板语法提供了一些内置方法,以助于快速的处理数据(过滤器最多只能有两个参数)
2.基本语法
{{ 变量|过滤器:参数}}
过滤器:会自动将竖杠左侧的变量当做第一个参数交给过滤器处理,右侧的当做第二个参数。
3.过滤器内置方法
<p>统计长度:{{ s|length }}</p>
# 统计长度:15
<p>加法运算:{{ i|add:123 }}、加法运算:{{ s|add:'heiheihei' }}</p>
# 加法运算:246、字符串加法运算:study work hard +every day
<p>日期转换:{{ s|date:'Y-m-d H:i:s' }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
# 文件大小:31.1 KB
<p>数据切片:{{ l|slice:'0:10' }}</p>
# 切片操作(支持步长)
<p>字符截取(三个点算一个):{{ s1|truncatechars:6 }}</p>
# 字符截取(包含三个点):模板语法提供...
<p>单词截取(空格):{{ s1|truncatewords:6 }}</p>
# 单词截取(不包含三个点 按照空格切):my name is objk my age is 18 and ...
<p>语法转义:{{ script_tag }}</p>
# <h1>今晚晚饭又有好多好吃的了</h1>(是不会识别前端标签的)
<p>语法转义:{{ script_tag|safe }}</p>
# 今晚晚饭又有好多好吃的了
# 如果不转移的话,那么无法识别前端标签,那么以下这种功能的情况就没有办法实现
<p>语法转义:{{ script_tag1|safe }}</p>
script_tag1 = '<script>alert(666)</script>'
# 也可以使用后端转
from django.utils.safestring import mark_safe
script_tag2 = '<script>alert(666)</script>'
res = mark_safe(script_tag2)
ps:有时候html页面上的数据不一定非要在html页面上编写了 也可以后端写好传入
'''django模板语法中的符号就两个 一个{{}} 一个{%%}
需要使用数据的时候 {{}}
需要使用方法的时候 {%%}
'''
4.模板语法标签(类似于python流程控制)
1.if判断
<body>
{% if 条件 %} 条件一般是模板语法传过来的数据 直接写名字使用即可
条件成立执行的代码
{% elif 条件1 %}
条件1成立执行的代码
{% else %}
条件都不成立执行的代码
{% endif %}
</body>
2.for循环
forloop 模板语法自带的变量名
{% for i in s %}
{% if forloop.first %}
<p>这是第一次哟~</p>
{% elif forloop.last %}
<p>这是最后一次!</p>
{% else %}
<p>{{ i }}</p>
{% endif %}
{% empty %}
<p>empty专门用来判断空的时候,当in后面是空的时候执行这个,给予提示</p>
{% endfor %}
解析:
forloop内置对象:运行结果解析
'counter0': 从0开始计数
'counter' : 从1开始计数
'first': True,判断循环的开始
'last' : Tues,判断循环的结束
3.with语法起别名
# with起别名
{% with d.hobby.3.info as nb %}
<p>{{ nb }}</p>
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
<p>{{ d.hobby.3.info }}</p>
{% endwith %}
解析:
可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
取别名后原来的名字也能正常使用
命名规范: 只能在with代码块儿的范围之内才能使用别名
5.自定义标签函数、过滤器、inclusion_tag
1.自定义过滤器,标签,inclusion_tog必须要有一下三步准备
1.在应用下创建一个名为templatetags文件夹
2.在该文件夹创建任意名称的py文件
3.在该py文件内编写自定义相关代码
from django.template import Library
register = Library()
2.自定义过滤器filter,最多能有俩个参数
# mytag.py
from django import template
register = template.Library()
# 参数 过滤器 过滤器名字
@register.filter(name='myfiltermyfilter')
def my_add(a, b):
return a + b
# index.html页面使用
加载自定义文件名
{% load mytag %}
<p>{{ i|myfilter:1 }}</p>
3.自定义标签(函数)
# 参数 标签(函数)标签(函数)名字
@register.simple_tag(name='mt')
def func(a, b, c, d):
return a + b + c + d
加载自定义文件名
{% load mytag %}
{% mt 1 2 3 4 %}
4.自定义inclusion_tag
当html页面某一个地方的页面需要传参数才能够动态的渲染出来,并且在多个页面上都需要使用到该局部
@register.inclusion_tag(filename='it.html')
def index(n):
html = []
for i in range(n):
html.append('第%s页'%i)
return locals() # 将html传给filename这个页面,然后可以在那个页面上使用
加载自定义文件名
{% load mytag %}
{% index 10 %}
filename是作用于一个页面,这个页面可以不是一个完整的页面,只是一部分,
6.模板的继承
1.什么是模板的继承
你需要事先在你想要使用的主页面上划定区域做好标记,之后在子页面继承的时候你就可以使用在主页面划定的区域,也就意味着,如果你不划定任何区域,那么你子页面将无法修改主页面内容
2.如何使用模板的继承
1.先在你想要继承的主页面上通过bolck划定你将来可能要改的区域,并做好标记
2.在子页面上继承extends,利用block自动提示选取你想要修改的内容区域标记名称
3.在子页面extends中写你要修改主页面标记区的代码
4.然后就可以让子页面的修改内容渲染到主页面的划定区域上
# 模板页面提前先写好将来可能要替换的内容
{% block 名字 %}
"""模板内容"""
{% endblock %}
# 新页面要基于模板页面替换的内容
{% extends 'html文件名' %}
{% block 名字 %}
"""子板内容"""
{% endblock %}
"""一般情况下母板中至少应该有三个区域使得扩展性更高!!! css content js"""
{% block css %}
<style>...</style>
{% endblock %}
{% block content %}
...
{% endblock %}
{% block js %}
<script>...</script>
{% endblock %}
'''子板中还可以使用母板的内容 {{ block.super }} '''
7.模板的导入
1.模板导入
将页面的某一个局部当成模块的形式
哪个地方需要就可以直接导入使用即可
2.导入格式
{% include '导入html文件名' %}