zoukankan      html  css  js  c++  java
  • 04--CBV源码分析 Django的settings源码分析 模板层

    CBV源码分析:

    前期准备:

    urls.py中
       url(r'^login/',views.MyLogin.as_view())
    views.py中
       from django.views import View
       class MyLogin(View):
           def get(self,request):
                print("from MyLogin get方法")
                return render(request,'login.html')
            def post(self,request):
                return HttpResponse("from MyLogin post方法")

    1-源码入口:

    url(r'^login/',views.MyLogin.as_view()),# 由于函数名加括号执行优先级最高,所以这一句话一写完会立刻执行as_view()方法
    @classonlymethod
    def as_view(cls, **initkwargs):  # cls就是我们自己的写的类 MyLogin
       def view(request, *args, **kwargs):
          self = cls(**initkwargs)  # 实例化产生MyLogin的对象  self = MyLogin(**ininkwargs)
          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)  # dispatch返回什么 浏览器就会收到什么    -------入口:dispatch方法
          # 对象在查找属性或者方法的时候 谨记一点 先从对象自己这里找  然后从产生对象的类里面找  最后类的父类依次往后
           return view
    # as_view()返回值是一个函数,相当于url(r'^login/',views.view) FBV和CBV在路由匹配上是一致的 都是url+函数的内存地址

    2-路由匹配执行view函数:

    def dispatch(self, request, *args, **kwargs):
        # 我们先以GET为例
        if request.method.lower() in self.http_method_names:  # 判断当前请求方法是否在默认的八个方法内
          # 反射获取我们自己写的类产生的对象的属性或者方法
          # 以GET为例  handler = getattr(self,'get','取不到报错的信息')
          # handler = get(request)
          handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
           handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # 直接调用我们自己的写类里面的get方法
        # 源码中先通过判断请求方式是否符合默认的八个请求方法 然后通过反射获取到自定义类中的对应的方法执行

    Django的settings 源码分析:

    前期准备:

    #django除了暴露给用户一个settings.py配置文件之外  自己内部还有一个全局的配置文件
    #我们在使用配置文件的时候 可以直接直接导入暴露给用户的settings.py也可以使用django全局的配置文件 并且后者居多
    from django.conf import settings
    #django的启动入口是manage.py
    # django在启动的时候 就会往全局的大字典中设置一个键值对  值是暴露给用户的配置文件的路径字符串
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")

    1-settings 即 LazySettings()对象:

    settings = LazySettings()  # 单例模式    

    2-LazySettings类内部:

    
    
    ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
    class LazySettings(LazyObject):
        def _setup(self, name=None):
        # os.environ你可以把它看成是一个全局的大字典
           settings_module = os.environ.get(ENVIRONMENT_VARIABLE)  # 从大字典中取值键为DJANGO_SETTINGS_MODULE所对应的值:day54.settings
        # settings_module = 'day54.settings'
           self._wrapped = Settings(settings_module)  # Settings('day54.settings')

    3-Settings 类内部:

    class Settings(object):
        def __init__(self, settings_module):  # settings_module = 'day54.settings'
        # update this dict from global settings (but only for ALL_CAPS settings)
        for setting in dir(global_settings):  # django全局配置文件
        # dir获取django全局配置文件中所有的变量名
        if setting.isupper():  # 判断文件中的变量名是否是大写 如果是大写才会执行/生效
           setattr(self, setting, getattr(global_settings, setting))  # 给settings对象设置键值对
        # 给settings对象设置键值对  settings[配置文件中大写的变量名] = 配置文件中大写的变量名所对应的值
        # store the settings module in case someone later cares
           self.SETTINGS_MODULE = settings_module  # 'day54.settings'
           mod = importlib.import_module(self.SETTINGS_MODULE)  # mod = 模块settings(暴露给用户的配置文件)
           for setting in dir(mod):  # for循环获取暴露给用户的配置文件中所有的变量名
               if setting.isupper():  # 判断变量名是否是大写
                  setting_value = getattr(mod, setting)  # 获取大写的变量名所对应的值
                  setattr(self, setting, setting_value)  # 给settings对象设置键值对
                  """
                  d = {}
                  d['username'] = 'jason'
                  d['username'] = 'egon'
                  用户如果配置了就用用户的
                  用户如果没有配置就用系统默认的
                  其实本质就是利用字典的键存在就是替换的原理 实现了用户配置就用用户的用户没配置就用默认的
                  """

     参考Django的settings源码的应用:

    新建项目:

    about_settings
      --|  conf文件夹
        --|  settings.py
      --|  lib文件夹
        --|  conf文件夹
          --| __init__.py       
    --| global_settings.py   --| start.py

    start.py:

    import os
    import sys
    
    
    BASE_DIR = os.path.dirname(__file__)
    sys.path.append(BASE_DIR)
    
    os.environ.setdefault('kkk','conf.settings')
    
    if __name__ == '__main__':
        from lib.conf import settings
        print(settings.NAME)

    gloabal_settings.py:

    NAME = "我是系统默认的name"

    settings.py:

    NAME = "我是用户自定义的NAME"

    __init__.py:

    import os
    import importlib
    from lib.conf import global_settings
    from conf import settings
    
    
    class Settings(object):
        def __init__(self):
            for setting in dir(global_settings):
                if setting.isupper():
                    setattr(self,setting,getattr(global_settings,setting))
    
            path = os.environ.get("kkk")
            model = importlib.import_module(path)
            for setting in dir(model):
                if setting.isupper():
                    setattr(self,setting,getattr(model,setting))
    
    
    settings = Settings()

     模板层:

    传值方式:

    # 方式1
        # 通过字典的键值对,以k,v键值对的形式进行传递:
        return render(request,'reg.html',{'n':n,'f':f})
    
    # 方式2
        # locals会将它所在的名称空间中的所有的变量全部传递给前端
        # 该方法虽然好用 但是在某些情况下回造成资源的浪费
        return render(request, 'reg.html', locals())

    支持的数据类型:

    <p>{{ n }}</p>    # 整型
    <p>{{ f }}</p>    # 浮点型
    <p>{{ s }}</p>    # 字符串
    <p>{{ l }}</p>    # 列表
    <p>{{ d }}</p>   # 字典
    <p>{{ t }}</p>    # 元组
    <p>{{ se }}</p>  # 集合
    <p>{{ index }}</p>
    # 传函数名,会自动加括号调用该函数,前端展示的是函数执行之后的返回值
    # 注意:如果函数需要参数的话  那么不好意思 模板语法不支持

     传递类对象:

    后台传入obj对象给前端:

        class Demo(object):
    
            def get_self(self):
                return '绑定给对象的方法'
    
            @classmethod
            def get_cls(cls):
                return '绑定给类的方法'
    
            @staticmethod
            def get_static():
                return '我是静态方法  其实就是函数'
        obj = Demo()

    前端调用类中方法:

    <p>{{ obj }}</p>
    <p>{{ obj.get_self }}</p>
    <p>{{ obj.get_cls }}</p>
    <p>{{ obj.get_static }}</p>
    <p>总结:django的模板语法 不支持给函数传参!!!</p>

     模板常用的标签过滤器:

    前端使用:

    <h1>模板语法之标签:内部原理(会将|前面的当做第一个参数传入标签中)</h1>
    <p>{{ l|length }}列表长度</p>
    <p>{{ n|length }}数字求长度不会报错,返回0</p>
    <p>{{ ss|default:'当|左边的变量为空就会返回|右边的值' }}  default跟你后端get方法类似</p>
    <p>{{ ss|default:'' }} default必须要有两个参数</p>
    <p>{{ file_size|filesizeformat }}进行文件大小转换k->M->G</p>
    <p>{{ info|truncatewords:3 }} 就是按空格截取,三个点不算</p>
    <p>{{ info1|truncatewords:3 }}</p>
    <p>{{ info|truncatechars:6 }}按字符截取内容 三个点也算</p>
    <p>{{ xxx|safe }}取消转义</p>
    <p>{{ yyy|safe }}</p>
    <p>{{ zzz }}</p>
    <p>{{ ctime }}</p>
    <p>{{ ctime|date:'Y-m-d' }}将时间按格式显示</p>
    <p>{{ n|add:100 }}数字n增加100</p>
    <p>{{ s|add:'hahah 翻车啦' }}字符串拼接</p>

    后台传入的值:

    file_size = 12312312
    info = 'my name is yyj and my age is 18'
    info1 = '傻大姐 撒旦 技术 大 萨达 了 奥斯卡 的健康两 三点卡是考虑到'
    xxx = '<h1>波波棋牌室</h1>'
    yyy = '<script>alert(123)</script>'
    # 后台进行取消转义
    from django.utils.safestring import mark_safe
    zzz = mark_safe('<h1>阿萨德搜啊第三款垃圾袋</h1>')
    from datetime import datetime
    ctime = datetime.now()

     逻辑相关:

    for循环和if判断:

     <p>for循环 </p>
    {% for foo in l %}
       <p>{{ forloop }}</p>
    {% endfor %}
    
     <p>if判断</p>
    {% if ' ' %}
    <p>xxx条件为true</p>
    
    {% else %}
        <p>xxx条件为false</p>
    {% endif %}
    
     <p>forloop使用,empty使用</p>
    {% for foo in '' %}
    
        {% if forloop.first %}
           <p>第一次循环</p>
        {% elif forloop.last %}
            <p>最后一次循环</p>
        {% else %}
            <p>普通循环</p>
        {% endif %}
    
        {% empty %}
        <p>当for循环的对象为空的时候 会走empty</p>
    {% endfor %}

    forloop属性:

    VariableDescription
    forloop.counter 当前循环的索引值(从1开始)
    forloop.counter0 当前循环的索引值(从0开始)
    forloop.revcounter 当前循环的倒序索引值(从1开始)
    forloop.revcounter0 当前循环的倒序索引值(从0开始)
    forloop.first 当前循环是不是第一次循环(布尔值)
    forloop.last 当前循环是不是最后一次循环(布尔值)
    forloop.parentloop 本层循环的外层循环

    取别名:

    <p>
        django模板语法在取值的时候 统一使用句点符
        {% with l.6.3.name as ttt %}  
    可以给一个比较复杂的取值操作取一个别名 之后在with语句中 就可以使用该别名
            {{ ttt }}
            {{ l.6.3.name }}
        {% endwith %}
    </p>

    keys,values,items操作:

    取字典的key
    {% for foo in d.keys %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    取字典的value
    {% for foo in d.values %}
        <p>{{ foo }}</p>
    {% endfor %}
    
    取键值对(元组)
    {% for foo in d.items %}
       <p>{{ foo }}</p>
    {% endfor %}

    自定义过滤器、标签、inclution_tag:

    自定义固定的三步:
      1.必须在你的应用下新建一个名为templatetags文件夹
      2.在该文件夹内新建一个任意名称的py文件
      3.在该py文件中固定先写下面两句代码:

    from django import template
    register = template.Library()
    # 自定义过滤器
    @register.filter(name='baby')
    def index(a,b):
    # 该过滤器只做一个加法运算 
        print('hello')
        return a + b
    
    # 自定义标签
    # 支持传多个值
    @register.simple_tag(name='jason')
    def xxx(a,b,c,year):
        return '%s?%s|%s{%s'%(a,b,c,year)
    
    # 自定义inclusion_tag
    """
    接收用户传入的参数  然后作用于一个html页面
    在该页面上渲染数据 之后将渲染好的页面
    放到用户调用inclusion_tag的地方
    """
    # 自定义inclusion_tag
    @register.inclusion_tag('bigplus.html')
    def bigplus(n):
        l = []
        for i in range(n):
            l.append('第%s项'%i)
        return {'l':l}

    bigplus.html:

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

    自定义过滤器,标签,inclution_tag的使用:

    <h1>自定义过滤器的使用
    自定义过滤器 只能有两个形参
        但是你可以在给第二个参数传值的时候 传一个字符串
    {% load mytag %} 需要先load自己创建的那个py文件
    </h1>
    {{ 123|baby:1}}
    {{ 123|baby:'1|2|3|4|5|6'}}
    
    <h1>自定义标签
    支持传多个参数  参数与参数之间 空格隔开
    </h1>
    {% load mytag %}
    {% jason 1 2 3 year=2 %}
    
    <h1>自定义inclusion_tag应用场景:
    当你的页面上有一部分html代码需要经常被各个地方使用  并且需要传参才能渲染出来,那么你可以把该html代码部分制作成一个inclusion_tag,任何页面都能使用
    </h1>
    {% load mytag %}
    {% bigplus 5 %}
    <br>
    {% bigplus 10 %}

    模板的继承:

    母板:

    <!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块,方便子页面替换。

    继承母板:

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

    替换母板中的块:

    {% block page-main %}
      <p>世情薄</p>
      <p>人情恶</p>
      <p>雨送黄昏花易落</p>
    {% endblock %}

    模板的导入:

    {% include 'navbar.html' %}
  • 相关阅读:
    三、Antd react 组件调用ref的用法获取实例
    三、gitextension 报错无法检出版本库的时候
    二、安装引入 antd
    一、React项目骨架搭建
    一、JAVA基础知识
    五、Maven创建Spring(IDEA2019-3-3)
    python爬取快手ios端首页热门视频
    接口测试之基础篇--http协议
    一些测试面试题
    性能测试一些相关的概念
  • 原文地址:https://www.cnblogs.com/yangjiaoshou/p/14234380.html
Copyright © 2011-2022 走看看