ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-09-04 17:02:24  阅读:158  来源: 互联网

标签:02 return get self 09 request html 2022 def


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有