网页伪静态、视图层、模板层

网页伪静态、视图层、模板层

一、网页伪静态

将动态网页伪装成静态网页,从而提升网页被搜索引擎收录的概率
表现形式:网址看着像一个具体的文件路径



def index(request):
    from django.shortcuts import HttpResponse
    return HttpResponse('哈哈哈,我不困')
urlpatterns = [
    path('index.html', view.index)
]

二、视图层

1、视图函数返回值

'''视图函数必须要返回一个HttpResponse对象'''
def index(request):
    # class HttpResponse(HttpResponseBase):
    #     pass
    # return HttpResponse('下雨了,凉快!')  # 类名加括号实例化产生一个对象

    # def render():
    #     return HttpResponse(content, content_type, status)
    # return render()  # 函数名加括号执行优先级最高,执行上面render函数,然后返回一个HttpResponse对象

    # def redirect():
    #                      HttpResponsePermanentRedirect是HttpResponse的子类
    #     redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
    #     return redirect_class()
    # >>>
    # class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
    #     pass
    return redirect()  # 通过继承HttpResponse子类

2、JsonResponse方法

对于JSON模块:
user_dict = {'name': 'jason老师', 'pwd': 123, 'hobby': ['sleep', 'eat', 'drink']}
json_str = json.dumps(user_dict, ensure_ascii=False)  # 防止编码问题
return HttpResponse(json_str)  # {"name": "jason老师", "pwd": 123, "hobby": ["sleep", "eat", "drink"]}


对于JsonResponse模块(django中使用):
主要源码(删除了部分):
class JsonResponse(HttpResponse):
    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)
        super().__init__(content=data, **kwargs)

1)字典使用:返回值的JsonResponse加入参数:json_dumps_params={'ensure_ascii': False}
from django.http import JsonResponse
user_dict = {'name': 'jason老师', 'pwd': 123, 'hobby': ['sleep', 'eat', 'drink']}
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})  # {"name": "jason老师", "pwd": 123, "hobby": ["sleep", "eat", "drink"]}

2)列表使用
user_list = ['jason', 'kevin', 'oscar']
return JsonResponse(user_list, json_dumps_params={'ensure_ascii': False})
# 报错:In order to allow non-dict objects to be serialized set the safe parameter to False.
# 报错已经提示:为了能够允许非字典的对象可以被序列化让 safe字段为False
return JsonResponse(user_list, safe=False, json_dumps_params={'ensure_ascii': False})  # ["jason", "kevin", "oscar"]

源码分析:

列表报错:

3、form表单携带文件数据

form表单需要具备的条件:
1)method属性值必须是:post
2)enctype属性值必须是:enctype="multipart/form-data"
3)后端获取文件数据的操作:request.FILES

单个文件:
def index(request):
    if request.method == 'POST':
        print('request.POST', request.POST)  # 普通数据
        # request.POST <QueryDict: {'username': ['jason']}>
        print('request.FILES', request.FILES)  # 文件数据
        # request.FILES <MultiValueDict: {'file': [<InMemoryUploadedFile: 博客图片文字美化.md (application/octet-stream)>]}>
        file_obj = request.FILES.get('file')
        # 如果是到多个文件,那么需要使用getlist获取文件列表,通过索引的方式获取即可
        print(file_obj.name)  # 打印我们的文件名
        with open(file_obj.name, 'wb') as f:  # w模式若没有文件则创建,创建一个和原本一样的文件
            for line in file_obj:  # 一行行写入内容
                f.write(line)
    return render(request, 'index.html')
html:<input type="file" name="file">

多个文件:
def index(request):
    if request.method == 'POST':
        print('request.POST', request.POST)  # 普通数据
        # request.POST <QueryDict: {'username': ['jason']}>
        print('request.FILES', request.FILES)  # 文件数据
        # request.FILES <MultiValueDict: {'file': [<InMemoryUploadedFile: 复习.md (application/octet-stream)>, <InMemoryUploadedFile: 今日考题.md (application/octet-stream)>]}>
        file_obj_list = request.FILES.getlist('file')
        for i in file_obj_list:
            with open(i.name, 'wb') as f:
                for line in i:
                    f.write(line)
    return render(request, 'index.html')
html:<input type="file" name="file" multiple>

单个文件:

多个文件:

4、FBV与CBV

FBV:基于函数的视图
def index(request):
    return HttpResponse()
路由:path('index/',views.index)

CBV:基于类的视图
from django import views
# 定义类
class MyView(views.View):
    def get(self, request):
        return HttpResponse('我是CBV里面的get方法')  # 当朝浏览器发送一个get请求自动触发

    def post(self, request):
        return HttpResponse('我是CBV里面的post方法')  # 当朝浏览器发送一个post请求自动触发
路由:path('func/', views.MyView.as_view())  # CBV路由匹配 类名点方法名
'''
不需要通过rquest.method方法来判断当前是什么请求,CBV会自动判断,如果是get请求方式自动触发get方法,如果是post请求方式自动触发post方法。
'''

5、CBV源码分析(重要)

源码分析入口:
path('func/', views.MyView.as_view())  # 自己写的类没有as_view这个方法,找父类View  |  as_view()函数名加括号执行优先级最高
# CBV路由匹配 类名点方法名(类点名字加括号可以看成对象点名字加括号,那么对象后面点的是方法)
# 要么是普通的函数,要么是绑定给类的方法,类来调,自动将类当做参数传进去
# '''
#     类里面定义的方法默认是绑定给对象使用的
#     @classmethod  绑定给类的方法 类来调将类当做第一个参数传入
#     @staticmethod   静态方法 无论谁来调用都必须按照普普通通的函数传参方式
# 类/对象点属性查找顺序是:先找自己,再找产生对象/这个类的父类
# '''

1)绑定给类的as_view方法
def as_view(...):
    def view(...):
        pass
    return view

2)CBV路由匹配的本质:跟FBV是一致的
>>>变形
path('func/', views.view)  # 当路由匹配到视图函数则执行view函数

3)访问func触发视图函数view执行
def view(...):
    self = cls(...)
	return self.dispatch(...)
'''涉及到对象点名字一定要确定对象是谁,再确定查找顺序'''

4)研究dispatch方法
def dispatch(...):
    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    return handler(...)  # return handler()

三、模板层

1、模板语法传值

1.模板语法传值
方式一:指名道姓  # 指名道姓传参,不浪费资源
return render(request, 'modal.html', {'name': name, 'age': age, 'gender': gender})

方式二:关键字:locals()
'''locals()将函数体里面所有的局部名称空间的名字传给前面的页面'''
return render(request,'modal.html',locals())


views.py:
def modal(request):
    name = 'jason'
    age = 18
    gender = 'male'
    # return render(request, 'modal.html', {'name': name, 'age': age, 'gender': gender})  # 优点指名道姓传的很精确,缺点就是如果传入的值太多那么很麻烦
    return render(request,'modal.html',locals())  # locals()将函数体里面所有的局部名称空间的名字传给modal.html页面
    # 缺点:若用到的名字很少造成浪费
    
modal.html:
{{ request }}
{{ name }}



2.模板语法传值的范围
1)基本数据类型直接传递使用
2)函数名的传递使用:模板语法会自动把这个函数名加括号,然后把函数运行后的返回值展示也页面
注意:函数如果有参数则不会执行也不会展示,模板语法不支持有参函数
3)类名的传递使用:模板语法会自动把这个类名加括号,然后把函数运行后的返回值展示也页面
4)象的传递则直接使用
PS:模板语法会判断每个名字是否可以调用,如果可以则调用
'''Django的模板语法在操作容器类型的时候值允许使用句点符'''

2、模板语法之过滤器(类似于python内置函数)

'''
语法结构
	{{ 数据对象|过滤器名称:参数 }}  过滤器最多只能额外传输一个参数
	
过滤器会自动把 | 前面的数据当做方法的第一个参数传入,若想传入第二个参数需要 : 
'''

PS:有时候html页面上的数据不一定非要在html页面上编写,也可以后端写好传入

html:
<p>统计长度:{{ s|length }}</p>
<p>加法运算:{{ i|add:123 }}、加法运算:{{ s|add:'hahaha' }}</p>
<p>日期转换(不要加百分号):{{ res|date:'Y-m-d H:i:s' }}</p>
<p>文件大小(将数字格式化成表示文件大小的单位):{{ file_size|filesizeformat }}</p>
<p>数据切片:{{ l|slice:'0:10' }}</p>
<p>字符截取(三个点算一个字符):{{ s1|truncatechars:6 }}</p>
<p>单词截取(按空格截取):{{ s1|truncatewords:6 }}</p>
# 重点:语法转义
<p>语法转义:{{ script_tag|safe }}</p>  <!--默认情况下不转,否则在脚本里写了死循环则页面绷了-->
<p>语法转义:{{ script_tag1|safe }}</p>
<p>后端转义:{{ res }}</p>

views.py:
    i = 123
    f = 11.11
    s = '加油加油'
    l = [11, 22, 33]
    d = {'name': 'jason', 'age': 18, 'others':[11,{'a':123,'b':[11,22,33]},22]}
    t = (111, 222, 333)
    se = {1111, 2222, 3333}
    b = True

    # import os
    # os.path.getsize()
    file_size = 2333334567

    s1 = 'my name is jason,my age is 18.my favorite fruit is apple.this is just so so'

    script_tag = '<h1>心静自然就能够干好了</h1>'
    script_tag1 = '<script>alert("心静")</script>'
    # 后端取消转义
    from django.utils.safestring import mark_safe
    script_tag2 = '<script>alert("可以从后端直接转义")</script>'
    res = mark_safe(script_tag2)

3、模板语法之标签(类似于python流程控制)

1.for
基本格式:
{% for 变量 in 值 %} 
	{{循环体}}
{% endfor %}

2.if
基本格式:
{% if判断语句 %}
	if表达式为真执行的代码块
{% elif 条件 %}
	if表达式为真执行的代码块
{% else %}
	所有条件都不满足执行的代码块
{% endif %}

3.with起别名
{% with 变量 as a %}  <!--给变量起了别名为a-->
    代码块
{% endwith %}

eg:
{% if s %}
    <p>哈哈哈</p>
{% elif l %}
    <p>嘿嘿嘿</p>
{% else %}
    <p>哦哦哦</p>
{% endif %}

{% for i  in l %}
    <p>{{ forloop }}</p>  <!--前端看是一个对象,后端看是一个字典-->
    {% if forloop.first %}
        <p>这是第一次</p>
    {% elif forloop.last %}
        <p>只是最后一次</p>
    {% else %}
        <p>{{ i }}</p>
    {% endif %}
    {% empty %}  # 判断in后面是不是为空
        <p>是个空,不能for循环</p>
{% endfor %}

{% with d.others.1.b.2 as a %}  <!--给d.others.1.b.2起了别名为a-->
    <p>{{ a }}</p>
{% endwith %}

4、自定义相关功能(了解)

'''
必须步骤:
1.在app应用下创建一个名字叫templatetags文件夹。
2.在该文件夹内创建一个任意名称的.py文件
3.在该py文件内必须写下两个语句
	from django import template
	register = template.Library()
4. 前端先使用{% load 自动模板语法文件的名字 %}
5. {{ 变量名|name指定名字(过滤器名字) }} 中 使用
'''

1.自定义过滤器
from django.template import Library
register = Library()
# 自定义过滤器(过滤器最多只有两个参数)
@register.filter(name='myfilter')
def my_add(a, b):
    return a + b

html页面中:
{% load mytag %}
{{ i|myfilter:1 }}  # 自定义过滤器:只能接收两个参数


2.自定义标签函数
from django.template import Library
register = Library()
# 自定义标签函数(可以接收任意的参数)
@register.simple_tag(name='mt')
def func(a,b,c,d):
    return a + b + c + d

html页面中:
{% load mytag %}
{% mt 1 2 3 4 %}  # 想传入几个参数就传入几个参数


3.自定义inclusion_tag
from django.template import Library
register = Library()
# 自定义inclusion_tag
@register.inclusion_tag(filename='it.html')
def index(n):
    html = []
    for i in range(n):
        html.append('第%s页' % i)
    return locals()  # locals()把html列表传给 it 这个页面,在页面上可以通过it用到html列表内的数据

html页面(完整页面):
{% load mytag %}
{% index 10 %}  

it页面(不完整页面):
<ul>
    {% for i in html %}
        <li>{{ i }}</li>
    {% endfor %}
</ul>

解释:在完整的页面上调用一个inclusion_tag,执行一个函数会有返回值给到一个不完整的html页面(inclusion_tag作用于一个不是完整的html页面(局部的页面)),不是完整的html页面生成之后再放回完整的页面上

5、模板的继承与导入

模板继承
模板页面 models.html
先在模板中通过block划定将来可以被修改的区域
{% block 名字 %}         
	可能需要替换的区域
{% endblock %}

子页面 xxx.html
{% extends 'models.html' %}  继承模板页面
{% block 名字 %}        引用
 	写新的代码替换
{% endblock %}

子页面可以重复父页面的内容:{{ block.super }}
"""
模板上最少应该有三个区域
	css区域、内容区域、js区域
子页面就可以有自己独立的css、js、内容
"""
{% block css %}         
	被替换的区域
{% endblock %}

{% block content %}         
	被替换的区域
{% endblock %}

{% block js %}         
	被替换的区域
{% endblock %}



1)母板:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Title</title>
  {% block page-css %}
  
  {% endblock %}
</head>
<body>

<h1>这是母板的标题</h1>

{% block page-main %}

{% endblock %}
<h1>母板底部内容</h1>
{% block page-js %}

{% endblock %}
</body>
</html>
'''我们通常会在母板中定义页面专用的CSS块和JS块,方便子页面替换。'''

2)继承母板:在子页面中在页面最上方使用下面的语法来继承母板
{% extends 'layouts.html' %}


3)块(block):
通过在母板中使用{% block  xxx %}来定义"块"。在子页面中通过定义母板中的block名来对应替换母板中相应的内容。
# 先在模板中通过block划定将来可以被修改的区域
{% block page-main %}
	可能需要替换的区域
{% endblock %}

4)组件:可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
{% include 'navbar.html' %}
模板导入
类似于将html页面上的局部页面做成模块的形式 哪个地方想要直接导入即可展示

eg:有一个非常好看的获取用户数据的页面 需要在网站的多个页面上使用
    策略1:拷贝多份即可
    策略2:模板的导入
   
使用方式
	{% include 'menu.html' %}
posted @   努力努力再努力~W  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示