首页 > 其他 > 详细

Django框架进阶3 视图层(render简单实现原理, CBV与FBV, CBV源码), django setting源码, importlib方法, 模板层(模板语法的传值,过滤器,标签,自定义过滤器及标签,模板的继承与导入), 基于django settings源码实现项目配置文件的 插拔式设计

时间:2020-01-08 02:36:04      阅读:99      评论:0      收藏:0      [点我收藏+]

render原理

from django.template import Context,Template
def ab_render(request):
    temp = Template(<h1>{{ user_dict}}{{user_dict.username}}{{user_dict.password}}</h1>)     # 相当于渲染页面
    user_dict = Context({user_dict:{username:jason,password:123}})
    res = temp.render(user_dict)
    return HttpResponse(res)

视图函数并不一定就是函数 也可以是类
FBV:基于函数的视图(例如上面的ab_render方法)
CBV:基于类的视图

 

CBV基本写法

views.py

 

from django.views import View

class MyLogin(View):
    def get(self,request):
        return render(request,login.html)
    def post(self,request):
        return HttpResponse(我是类里的post方法)

 

urls.py

# CBV路由配置
url(r^login/,views.MyLogin.as_view())

  朝login提交get请求会自动执行MyLogin里面的get方法
  而提交post请求也会自动执行MyLogin里面的post方法
  为什么MyLogin针对不同的请求方法能够自动执行对应的方法

 

研究源码的突破口

  url(r‘^login/‘,views.MyLogin.as_view())

 

  猜想
    as_view要么是类里面定义的普通函数 @staticmethod
    要么是类里面定义的绑定给类的方法 @classmethod

  看源码发现是绑定给类的方法

技术分享图片

# CBV路由配置
url(r^login/,views.MyLogin.as_view())
# 等价于
# url(r‘^login/‘,views.view)    # FBV与CBV在路由匹配上本质是一样的 都是路由与函数内存地址的对应关系

技术分享图片

 

 

 技术分享图片

 

 

 

Django setting源码

django暴露给用户一个可以自定义的配置
但是内部也有默认的配置

from django.conf import global_settings,settings    # global_settings全局设定  setting用户设定 点击可以查看源码,完整设定

用户配置了就用用户的 用户没有配就用默认的

点开settings,内部为

settings = LazySettings()    # 单例模式

 技术分享图片

 os大字典在manage.py中一开始就赋(因为manage.py作为管理文件是项目一开始就运行的)

技术分享图片

 

importlib方法:

技术分享图片

 b.py内容

name = jason

a.py内容

# from conf import b
# print(b.name)

import importlib
res = conf.b
md = importlib.import_module(res)   # 把字符串转换为路径,导入
# 该方法最小单位是模块  不能是模块里面的名字
print(md.name)    # jason

 

模板层

模板语法符号

{{}} 变量相关
{%%} 逻辑相关

注意: 下面是模板语法的注释 这个注释前端是看不见的。浏览器检查只能看到 <!----> 这类注释

{# ... #} 

模板层之模板传值

  python基本数据类型全部支持传递给html文件
  对象
    后端给html文件传递数据的两种方式
    1.指名道姓
      return render(request,‘index.html‘,{‘n‘:n,‘f‘:f})

    2.locals() # 会将当前名称空间中所有的变量名全部传递给html页面
      return render(request,‘index.html‘,locals())

    html页面上 如何获取到后端传递过来的数据
      {{ 变量名 }}

例:

技术分享图片
def index(request):
    # python所有数据类型都支持传递给html页面
    n = 11
    f = 11.11
    s = hello world
    l = [1,2,3,4,5,6]
    d = {username:jason,password:123}
    t = (1,2,3,4,5,6,7)
    se = {1,2,3,4,5,6}
    b = True

    # return render(request,‘index.html‘,{‘n‘:n,‘f‘:f}) 给模板传递数据
    return render(request,index.html,locals())    # 会将当前名称空间中所有的变量名全部传递给html页面
Views.py
技术分享图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<p>{{ n }}</p>
{#模板语法的注释  这个注释前端是看不见的#}
<!--浏览器检查能够看到-->
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
</body>
</html>
index.html

  函数

注意:html中函数名会自动加括号执行 展示的是函数的返回值。并且模板语法不支持给函数传参

技术分享图片
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from django.template import Context,Template

def index(request):
    def func():
        print(‘func被执行了‘)
        return ‘from func‘

    # return render(request,‘index.html‘,{‘n‘:n,‘f‘:f}) 给模板传递数据
    return render(request,‘index.html‘,locals())    # 会将当前名称空间中所有的变量名全部传递给html页面
Views.py
技术分享图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{#<p>{{ n }}</p>#}
{#模板语法的注释  这个注释前端是看不见的#}
<!--浏览器检查能够看到-->
<p>函数名会自动加括号执行 展示的是函数的返回值:{{ func }} 模板语法不支持给函数传参</p>
</body>
</html>
index.html

  
    函数和对象会自动加括号
    # 模板语法不支持传参

技术分享图片
def index(request):
    # python所有数据类型都支持传递给html页面

    class MyClass(object):
        def get_self(self):
            return from self

        @staticmethod
        def get_func():
            return from func

        @classmethod
        def get_cls(cls):
            return from cls

    obj = MyClass()

    # return render(request,‘index.html‘,{‘n‘:n,‘f‘:f}) 给模板传递数据
    return render(request,index.html,locals())    # 会将当前名称空间中所有的变量名全部传递给html页面
Views.py
技术分享图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{#<p>传类名 也会自动加括号实例化{{ MyClass }}</p>#}
<p>{{ obj }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_cls }}</p>

</body>
</html>
index.html

  取值

    django模板语法取值 只有一种操作方式 句点符 .
    点索引
    点键

<p>{{ l.2 }}</p>
<p>{{ d.username }}</p>
<p>{{ d.password }}</p>
<p>{{ d.hobby.1.username.1 }}</p>

例:

技术分享图片
def index(request):
    # python所有数据类型都支持传递给html页面
    n = 11
    f = 11.11
    s = ‘hello world‘
    l = [1,2,3,4,5,6]
    d = {‘username‘:‘jason‘,‘password‘:123,‘hobby‘:[‘read‘,{‘username‘:[‘jason‘,‘egon‘]}]}
    t = (1,2,3,4,5,6,7)
    se = {1,2,3,4,5,6}
    b = True
  # return render(request,‘index.html‘,{‘n‘:n,‘f‘:f}) 给模板传递数据
    return render(request,‘index.html‘,locals())    # 会将当前名称空间中所有的变量名全部传递给html页面
Views.py
技术分享图片
<p>取值</p>
<p>{{ l.2 }}</p>
<p>{{ d.username }}</p>
<p>{{ d.password }}</p>
<p>{{ d.hobby.1.username.1 }}</p>
index.html 精髓部分

 

模板语法之过滤器   |

|length
|add
|default
|truncatechars
|truncatewords
|filesizeformat
|slice
|date
|safe
<p>过滤器  |左边的会当做过滤器的第一个参数 过滤器名右边的会当做过滤器的第二个参数</p>
        <p>求数据长度:{{ s|length }}</p>
        <p>加法运算:{{ n|add:10 }}、{{ s|add:13132 }}、{{ s|add:‘DSB‘ }}</p>
        <p>默认值(判断值是否为空):{{ b|default:‘这个b布尔值是True‘ }}、{{ ff|default:‘这个ff布尔值是Flase‘ }}</p>
        <p>截取字符(截取5个字符 三个点也算):{{ s|truncatechars:8 }}</p>
        <p>截取单词(截取8个单词 三个点不算):{{ ss|truncatewords:8 }}、{{ sss|truncatewords:4 }}</p>
        <p>文件大小:{{ file_size|filesizeformat }}</p>
        <p>切片操作:{{ s|slice:‘0:2‘ }}、{{ s|slice:"0:8:2" }}</p>
        <p>日期格式化:{{ ddd|date:‘Y年/m月/d日‘ }}</p>    <!--注意世界戳无法被时间格式化-->
        <p>转义:{{ res|safe }}、{{ res1 }}、后端直接标识安全:{{ res2 }}</p>  <!--直接写res无法转义是因为计算机为了保证安全,不可随便转义-->

前后端取消转义  

前端
  |safe
后端

from django.utils.safestring import mark_safe    # 先导入模块
mark_safe(<h1>安全滴</h1>)

总结:前端代码不一定非要在前端页面写,可以在后端写好传递给前端页面使用
这样的话 你就可以利用到后端更加多的逻辑语法

 

模板语法之标签  (逻辑相关)

查看内部fooloop变量内容

<p>标签</p>
{% for foo in l %}
    <p>{{ forloop }}</p>

{% endfor %}

技术分享图片

{% for foo in l %}  <!--l = [1,2,3,4,5,6]-->
        {% if forloop.first %}
            <p>这是我的第一次</p>
        {% elif forloop.last %}
            <p>这是最后一次了啊~</p>
        {% else %}
            <p>{{ foo }}</p>
        {% endif %}
        {% empty %}
        <p>for循环的对象内部没有值</p>
    {% endfor %}

注意:当一个值获取的步骤非常繁琐 但是又需要在很多地方用到 我们可以起别名来简化代码,别名只能在with内使用

<p>当一个值获取的步骤非常繁琐  但是又需要在很多地方用到  我们可以起别名来简化代码</p>
{% with d.hobby.1.username.1 as eg %}   {# 不需要加双括号 #}
    <p>别名只能在with内使用:{{ eg }}</p>
    <p>{{ d.hobby.1.username.1 }}</p>
{% endwith %}

 

自定义过滤器 标签 inclusion_tag

先完成以下前期准备工作
1.在应用名下新建一个名字必须叫templatetags文件夹
2.在该文件夹内新建一个任意名称的py文件(eg:mytag)
3.在该文件内 必须先写以下两句代码

from django.template import Library
            
register = Library()

自定义过滤器(最多支持2个参数)

 app01/templatetags/mytage.py

# 自定义过滤器
@register.filter(name=my_sum)
def index(a,b):
   return a + b

 templates/index.html

<p>自定义过滤器的使用</p>
{% load mytag %}
<p>{{ 10|my_sum:90 }}</p>   <!--只能写两个参数-->

自定义标签(支持多个参数)

 app01/templatetags/mytage.py

# 自定义标签
@register.simple_tag(name=my_baby)
def xxx(a,b,c,d):
    return %s?%s?%s?%s?%(a,b,c,d)

 templates/index.html

<p>自定义标签的使用</p>
{% load mytag %}
<p>{% my_baby 1 2 3 ‘hello world‘ %}</p>    

注意:自定义过滤器可以在逻辑语句中使用,而自定义的标签不可以

 templates/index.html

{% load mytag %}
{% if 10|my_sum:100 %}
    <p>条件成立</p>
{% endif %}

 

自定义inclusion_tag

app01/templatetags/mytage.py

# 自定义inclusion_tag
@register.inclusion_tag(demo.html,name=myin)
def index1(n):
    l = []
    for i in range(n):
        l.append(i)
    # 将列表传递给demo.html
    # return locals()
    return {l:l}

 templates/index.html

<p>自定义inclusion_tag的使用</p>
{% load mytag %}
{% myin 10 %}   <!--调用想要渲染的模块区域,并传值,然后放到这个区域-->
</body>
</html>

 templates/demo.html

<ul>
    {% for foo in l %}
    <li>{{ foo }}</li>
    {% endfor %}
</ul>

 

模板的继承

某一个页面大部分区域都是公用的 那这个页面就可以作为模板页面
当别人继承这个页面之后 如何修改对应的区域

先在模板页面上通过block实现划定区域

{% block content %}    
    模板页面内容
{% endblock %}

子页面中先导入整个模板

{% extends ‘模板页面.html‘%}
修改特定的区域  通过实现划定好的区域名称
{% block content %}
    子页面内容
{% endblock %}

通常情况下 模板页面页面应该起码有三块区域

{% block css %}    
    模板页面内容
{% endblock %}
{% block content %}    
    模板页面内容
{% endblock %}
{% block js %}    
    模板页面内容
{% endblock %}
# 模板的block块越多 可扩展性越高

支持子页面调用父页面对应区域的内容 并且可以无限次调用

{{ block.super }}

 

模板的导入

将html页面当做模块使用 哪里需要导哪里  这个html页面通常都不是完整的 只是一个局部样式

{% include ‘left.html‘ %}

 

基于django settings源码实现项目配置文件的 插拔式设计

技术分享图片

conf/settings.py

# NAME = ‘我是暴露给用户的配置文件‘

lib/conf/__init__.py

技术分享图片
import importlib
import os
from lib.conf import global_settings


class Settings(object):
    def __init__(self):
        # 先循环遍历项目默认的全局配置文件
        for name in dir(global_settings):
            # 判断变量名是否是大写
            if name.isupper():
                # 键值对设置给对象
                k = name  # NAME
                v = getattr(global_settings,name)  # jason
                setattr(self,k,v)

        # 先获取暴露给用户的配置文件的字符串路径
        module_path = os.environ.get(‘xxx‘)  # conf.settings
        # 里面importlib模块 导入settings文件
        md = importlib.import_module(module_path)  # md = settings

        # 同上操作
        for name in dir(md):
            # 判断变量名是否是大写
            if name.isupper():
                # 键值对设置给对象
                k = name  # NAME
                v = getattr(md,name)  # jason
                setattr(self,k,v)
View Code

lib/conf/global_settings.py

NAME = ‘我是项目默认的配置文件‘

start.py

技术分享图片
import os
import sys


BASE_DIR = os.path.dirname(__file__)
sys.path.append(BASE_DIR)


if __name__ == ‘__main__‘:
    # 项目启动 就应该朝全局的大字典中设置键值对
    os.environ[‘xxx‘] = ‘conf.settings‘
    from lib.conf import settings
    print(settings.NAME)
View Code

Django框架进阶3 视图层(render简单实现原理, CBV与FBV, CBV源码), django setting源码, importlib方法, 模板层(模板语法的传值,过滤器,标签,自定义过滤器及标签,模板的继承与导入), 基于django settings源码实现项目配置文件的 插拔式设计

原文:https://www.cnblogs.com/ludingchao/p/12163807.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!