其他分享
首页 > 其他分享> > 【2022-09-02】Django框架(四)

【2022-09-02】Django框架(四)

作者:互联网

Django框架(四)

Django框架之伪静态

概念

静态文件:数据是写死,永远不会修改
 
伪静态:将一个动态页面伪装成静态页面
 
# 为什么要伪装?
伪装的目的在于增大本网站的seo查询力度
并且增加搜索引擎收藏本网站的概率:如果搜索引擎发现是一个静态网页,说明这个页面不会再修改了,那么搜索引擎就会把这个网站收录起来,如果有用户搜索该网页相关的信息,那么搜索引擎就会优先把这个网页展示给用户。(这样就大大增加了网站的点击率,得到更多的流量)
 
# 搜索引擎本质上就是一个巨大的爬虫程序
如:
百度:他在互联网爬取到用户搜索的所有相关信息展示给用户
 
 
总结:无论怎么优化,怎么处理,还是干不过RMB玩家。(付费做广告的永远会放在搜索引擎的最前面)

实现

只需要在urls.py配置路由时加一个.html后缀即可以

path('index.html',view.index)

视图层

视图函数返回值

视图函数的返回值问题
	视图函数必须返回一个HttpResponse对象
	注意HttpResonse其实是一个类
    	class HttpResponse(HttpResponseBase):
            pass
   		def render():
            return HttpResponse(...)
       def redirect(to, *args, permanent=False, **kwargs):
        redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
        return redirect_class(resolve_url(to, *args, **kwargs))

JsonResponse对象

作用:序列化成json格式的数据
json格式的数据有什么作用:
	前后端数据交互需要使用用到json作为过渡,实现跨语言传输数据
 
# 补充:
    前端序列化:
    JSON.stringify()
    JSON.parse()
 
    后端序列化:
    json.dumps()
    json.loads()
# 使用json模块序列化
 
import json
 
def ab_json(request):
    user_dict = {'username':'gary我是张三','password':'123','hobby':'girl美女'}
    # 将字典序列化为json格式的字符串
  	json_str = json.dumps(user_dict)
    # 将序列化后的字符串返回
    return HttpResponse(json_str)

# 解决上述问题:
import json
 
def ab_json(request):
    user_dict = {'username':'gary我是张三','password':'123','hobby':'girl美女'}
    # 将字典序列化为json格式的字符串
  	json_str = json.dumps(user_dict,ensure_ascii=False)  # 将内置编码修改
    # 将序列化后的字符串返回
    return HttpResponse(json_str)

# django提供的模块
 
from django.http import JsonResponse
def ab_json(request):
    user_dict = {'username':'gary我是张三','password':'123','hobby':'girl美女'}
 
    return JsonResponse(user_dict)

# 解决上述问题
from django.http import JsonResponse
def ab_json(request):
    user_dict = {'username':'gary我是张三','password':'123','hobby':'girl美女'}
    return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})

# 研究其他形式是否可以序列化:
 
from django.http import JsonResponse
def ab_json(request):
    l = [11,22,33,44,55]
   
    return JsonResponse(l)

from django.http import JsonResponse
def ab_json(request):
    l = [11,22,33,44,55]
   
    return JsonResponse(l,safe=False)
# 默认只能序列化字典 序列化其他需要加safe参数

request对象方法

request.method  # 获取请求方式
request.POST	# 获取普通键值对形式的普通文件
request.GET		# 获取GET请求数据
request.FILES	# 获取文件数据
 
request.path	# 只能获取路由
request.get_full_path()  # 不但获取到路由还能获取到路由后面的参数
request.body    # 原生浏览器发过来的二进制数据

form表单提交文件类型数据

# form表单上传文件类型的数据注意事项:
method必须指定成post
enctype必须换为:multipart/form-data
urls.py
urlpatterns = [
    url(r'^ab_file/',views.ab_file)
]
form.html
<form action="" method="post" enctype="multipart/form-data">
    <p>test:<input type="text" name="test"></p>
    <p>file:<input type="file" name="file"></p>
    <input type="submit">
</form>
views.py
def ab_file(request):
    if request.method == 'POST':
        print(request.POST)  # 著获取普通的键值对数据 文件不行
        print(request.FILES)  # 获取文件数据
        file_obj = request.FILES.get('file')  # 获取文件对象
        print(file_obj.name)  # 拿到文件名字
        with open(file_obj.name,'wb') as f:
            for line in file_obj:
                f.write(line)
 
    return render(request,'form.html')

FBV与CBV

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方法')
            def post(self, request):
                return HttpResponse('我是CBV里面的post方法')
         path('func/', views.MyView.as_view())
         """
         CBV会自动根据请求方式的不同匹配类中定义的方法并自动执行
         """

CBV源码剖析

准备工作:做一个简单的CBV来研究路由层(urls.py)到底是怎么触发视图层(views.py)的类方法的。
views.py
from django.views import View
 
 
class MyLogin(View):
    def get(self,request):
        return render(request,'login.html')  # 收到get请求走这个方法返回一个页面
 
 
    def post(self,request):
        return HttpResponse('post请求')   # 收到post请求走这个返回一个'字符串'
login.html
<form action="" method="post">
    <input type="submit">   <!--点击提交按钮触发post请求-->
</form>
urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'login/',views.MyLogin.as_view())
]
那么我们如何去研究呢?
# 我们先来探讨url
url(r'login/',views.MyLogin.as_view())
 
# 我们可以看到他与FBV的区别就在于后面所对应的 类名.as_view()
 
我们知道在python中一切皆'对象',那么类使用(.)的方式时,类(.)的是肯定是一个属性或者一个方法
那么说明as_view()要么是一个属性要么是一个方法。
但是他加了一个(), 我们可猜测他是一个方法,他就相当于'函数名+()'
 
# 补充: 函数名/方法名 加括号()执行优先级最高,
这就就相当于在用户访问路由后缀为login/时,就会立刻执行views下的MyLogin类下的as_view()
# 那么我们就来研究这个as_view()到底是什么样的逻辑呢。
 
猜测:as_view()  # 要么是被@staticmethod修饰的静态方法
	 as_view()  # 要么是被@classmethod修饰的类方法
    
# 通过ctrl+左键的方式点进去看一下他的源码

@classonlymethod
def as_view(cls, **initkwargs):
    
# 通过源码我们可以看到他确实是一个绑定给类的方法,类来调用,就把类当作第一个参数传入
我们来研究一个这个函数:

函数的返回值:view  # 为内部函数的函数名
# 那么在启动django的时候就会立刻执行as_view方法,as_view的返回值为view
那么就相当于:
url(r'login/',views.MyLogin.as_view())
同等于:
url(r'^login/,views.view')  # 那么这个结果是不是和FBV模式一摸一样
 
# 通过这一点:CBV与FBV在路由匹配上本质是一样的。都为(路由,views.函数内存地址)
那么在用户输入路由后缀为login/的时候就会自动触发view方法。
研究view方法
def view(request, *args, **kwargs):
    self = cls(**initkwargs)  # cls为我们自己写的类(MyLogin) 加括号后产生对象
    # 相当于:self = MyLogin(**initkwargs)  # 类加()就产生一个我们自己写的类的对象self
    if hasattr(self, 'get') and not hasattr(self, 'head'):   # 反射
        self.head = self.get
        self.request = request   # 这里是给对象赋值一些属性
        self.args = args
        self.kwargs = kwargs
        return self.dispatch(request, *args, **kwargs)
    # 对象.一个属性 :查找属性的顺序:先去对象自己找,再去产生对象的类里面找,之后再去父类里找
    # 一定要明白当前的self是谁。(这里self为我们自己写的类产生的对象)
    # 那么这里没有dispatch方法 ,我们自己写得类里面也没有,那么就去类继承得父类View查看有没有该方法
    
# 那么我们就去找一下这个dispatch属性/方法
研究:View: dispatch
# 很明显在上述的view方法里没有,我们自己写的MyLogin类里肯定也是没有的,那么我们就来研究视图层:我们所编写的类所继承的(View)
class MyLogin(View):   # 同样通过ctrl+鼠标左键的方式点进去看一下

# 我们来研究一下这个代码 
    
    def dispatch(self, request, *args, **kwargs):
        # 获取当前请求方式并转为小写 然后比对当前比对是否合法(这里就以'GET'请求为例)
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        # getattr反射:通过字符串来操作对象的属性或者方法(那么第二个参数位置即为'get')如果'get'方法有值就返回get方法得返回值,我们在定义类得时候,定义了get方法的,所有就会返回get方法得返回值
        # 括号内参数解释:(self:自己写的类产生的对象,'get',当找不到get方法的时候就会找第三个参数)
        # 那么现在就相当于:
            # handler = getattr(我们自己写的类产生的对象,'get','当找不到get属性或者方法就会用第三个参数返回该参数对应方法得返回值')
            # get如果存在:hanler就相当于:handler = 我们自己写的get方法
        else:
            handler = self.http_method_not_allowed  # 找不到get方法走的方法(抛出异常)
        return handler(request, *args, **kwargs)   # 自动调用我们自己写的get方法
 
    #  那么post方法同理
这样就疏通了CBV的执行流程。其实内部还是FBV

模板层

templates模板语法的传值

# 模板语法的格式:
    {{ }} :跟变量相关的时候使用
    {% %} :跟逻辑相关的时候使用
基本语法传值研究:

研究函数:
def func():
        print('无参函数')
        return '无参函数返回值'
    def func1(xx):
        print('有参函数')
        return '有参函数返回值'
 
# 特点:传递函数名会自动加括号调用,但是模板语法不支持给函数传额外的参数

研究类:
class Myclass():
        def get_self(self):
            return 'self'
 
        @staticmethod  # 转换为普通函数
        def get_func():
            return 'func'
 
        @classmethod   # 绑定给类的方法
        def get_class(cls):
            return 'cls'
 
        # 对象被展示到html页面上,也相当于执行了打印操作也会触发__str__方法a
        def __str__(self):
            return '是否加载呢'
 
    obj = Myclass()  # 类名加括号实例化产生一个对象

验证:模板语法的取值方式:

总结:
# django模版语法的取值 是固定的格式 只能采用“句点符” .
 
# 即可以点键也可以点索引 还可以两者混用

模板语法传值范围

模板语法传值的范围
	基本数据类型直接传递使用
 	函数名的传递会自动加括号执行并将返回值展示到页面上
    	注意函数如果有参数则不会执行也不会展示 模板语法不支持有参函数
   类名的传递也会自动加括号产生对象并展示到页面上
   对象的传递则直接使用即可
   ps:模板语法会判断每一个名字是否可调用 如果可以则调用!!!
"""django的模板语法在操作容器类型的时候只允许使用句点符"""

模板语法过滤器

模板语法过滤器(类似于python内置函数)
	<p>统计长度:{{ s|length }}</p>
    <p>加法运算:{{ i|add:123 }}、加法运算:{{ s|add:'heiheihei' }}</p>
    <p>日期转换:{{ s|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>
    from django.utils.safestring import mark_safe
    script_tag1 = '<script>alert(666)</script>'
    res = mark_safe(script_tag1)
    ps:有时候html页面上的数据不一定非要在html页面上编写了 也可以后端写好传入
'''django模板语法中的符号就两个 一个{{}} 一个{%%}
	需要使用数据的时候 {{}}
	需要使用方法的时候 {%%}
'''  

模板语法之标签的使用(if,for..)

if判断
语法结构:
{% if b %}     # 判断b是否为True
    <p>if</p>  # 条件成立执行
{% elif s %}  # 上述条件为False判断elif条件
    <h1>elif</h1>  # elif条件成立执行
{% else %}   # 上述都为False
    <p>else</p>
{% endif %}  # 结束语法
 
 
# 可直接输入if按Tab键补全语法结构

for循环
语法结构:
{% for 变量名 in 待循环集 %}
	循环体代码
{% endfor %}
 
# 可直接输入for按Tab键补全for循环的语法结构
 
eg:
{% for foo in l %}
    {{ foo }}
{% endfor %}

关键字:forloop
# forloop关键字可标识数据的状态
 
first:标识for循环是第一次
last :标识for循环时最后一次
counter0 : 索引
counter  : 计数
revcounter :倒序计数
revcounter0:倒序索引

for与if混合使用
{% for foo in lll %}
    {% 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 %}   # keys
    <p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}  # values
    <p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}   # items
    <p>{{ foo }}</p>
{% endfor %}

with起别名
{% with dd.hobby.2.info as nb  %}
    <p>{{ nb }}</p>
    # 在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
    <p>{{ dd.hobby.2.info }}</p>   # 也可以使用之前的
{% endwith %}

自定义过滤器、标签、inclusion_tag

自定义前注意事项:
1. 在应用下创建一个名字'必须'为templatetags文件夹
2. 在该文件夹内创建'任意'名称的py文件 比如:mytag.py
3. 在该py文件内'必须'编写下面两句话
    from django import template
    register = templante.Library()
# 注:变量名也不能改变
自定义过滤器:
# 关键字:@register.filter(name='自定义名字')
 
eg:
# 自定义过滤器:
from django import template
 
 
register = template.Library()
 
@register.filter(name='mysum')  
def my_sum(v1,v2):
    return v1+v2
 
 
# 使用
{% load mytag %}  # 导入文件
 
<p>{{ n|mysum:s }}</p>   # 字符串拼接
<p>{{ i|mysum:222 }}</p>   # 数字相加

自定义标签:
# 自定义标签
@register.simple_tag(name='plus')
def index(a,b,c,d):
    return '%s-%s-%s-%s'%(a,b,c,d)
 
# 具体使用
{% load mytag %}
<p>{% plus 'gary' 28 'age' 20 %}</p>

自定义inclusion_tag
# 内部原理
	先定义一个方法 
	在页面上调用该方法 并且可以传值
	该方法会生成一些数据然后传递给一个html页面
	之后将渲染好的结果放到调用的位置
    
# 自定义inclusion_tag
 
@register.inclusion_tag('left_menu.html')
def left(n):
    data = ['标签{}'.format(i) for i in range(n)]  # 列表生成式
    # 将data传递给'left_menu.html'
    # 第一种方式:
    # return {'data':data}
    # 第二种方式:
    return locals()

# left_menu.html
 
<ul>
    {% for foo in data %}   # for循环data列表
        <li>{{ foo }}</li>   # 添加到li标签内
    {% endfor %}
</ul>

# 使用
{% load mytag %}   # 导入文件
 
{% left 10 %}    # 参数可指定li标签的个数

模板的继承与导入

模板继承
准备工作:
home.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>
 
    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <form class="navbar-form navbar-left">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
          </ul>
        </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="list-group">
              <a href="/home/" class="list-group-item active">
                首页
              </a>
              <a href="/login/" class="list-group-item">登录</a>
              <a href="/reg" class="list-group-item">注册</a>
 
            </div>
        </div>
        <div class="col-md-9">
            <div class="panel panel-primary">
              <div class="panel-heading">
                <h3 class="panel-title">Panel title</h3>
              </div>
              <div class="panel-body">
                <div class="jumbotron">
                  <h1>Hello, world!</h1>
                  <p>...</p>
                  <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
                </div>
              </div>
            </div>
        </div>
 
    </div>
 
 
</div>
</body>
</html>
# 先搭一个简单的框架
# 需求:
点击登录/注册:只改变右侧的巨幕部分其他部分不改变

初始继承:
views.py
def home(request):
    return render(request,'home.html')
 
def login(request):
    return render(request,'login.html')
 
def reg(request):
    return render(request,'reg.html')
# 继承关键字:extends 
{% extends 'home.html' %}   # 直接继承home.html

我们可以看到:只需要一个继承就可以完全继承home页面的所有内容
但是:这并不符合我们的要求 登录/注册页面肯定要有变化 那么我们怎么知道那一片区域进行修改呢
# 这里就需要在模板home.html提前定义好区域这里就要用到指定的模板语法
block模板语法
# 继承了之后子页面跟模版页面长的是一模一样的 你需要在模版页面上提前划定可以被修改的区域
# block会提前定义好区域
格式:
{% block content %}
	标识代码块
{% endblock %}

login.html
{% extends 'home.html' %}
 
{% block content %}
    <h1 class="text-center">登录页面</h1>
    <form action="">
        <p>username:<input type="text" name="username" class="form-control"></p>
        <p>password:<input type="password" name="password" class="form-control"></p>
        <input type="submit" class="btn btn-success">
    </form>
{% endblock %}
reg.html
{% extends 'home.html' %}
 
{% block content %}
    <h1 class="text-center">注册页面</h1>
    <form action="">
        <p>username:<input type="text" name="username" class="form-control"></p>
        <p>password:<input type="password" name="password" class="form-control"></p>
        <input type="submit" class="btn btn-danger">
    </form>
{% endblock %}

# 一般情况下模版页面上应该至少有三块可以被修改的区域
1.css区域
2.html区域
3.js区域
 
  # 每一个子页面就都可以有自己独有的css代码 html代码 js代码
  
"""
一般情况下 模版的页面上划定的区域越多 那么该模版的扩展性就越高
但是如果太多 那还不如自己直接写
"""

模板导入
# 将页面的某一个局部当成模块的形式,那个地方需要就可以导入使用即可
# 关键字:include
# 格式:
    {% include 'html页面' %}
    
# eg:

标签:02,return,get,self,09,request,html,2022,def
来源: https://www.cnblogs.com/dy12138/p/16650966.html