zoukankan      html  css  js  c++  java
  • Django的View(视图)-settings源码的解析-模板层-模板语法

    FBV与CBV

      视图函数并不只是指函数,也可以是类

    FBV:基于函数的视图,类似面向函数式编程

    CBV:基于类的视图,类似面向对象编程

     研究解析render源码:

      render:返回html页面;并且能够给该页面传值

    分析:FBV视图原理

    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    
    from django.template import  Template,Context
    # FBV解析
    def index(request):
        temp = Template('<h1>{{ user }}</h1>')
        con = Context({"user":{"name":'gets','password':'123456'}})
        res =temp.render(con)
        print(res)
        return  HttpResponse(res)

    print的结果:

     可以分析出利用关键字:Context 先获取数据格式,通过con = Context({"user":{"name":'gets','password':'123456'}})转成字典形式传给前端显示

     

    分析CBV视图原理:类方法

    问题:基于CBV的视图函数,get请求来就会走类里面get方法,post请求来就会走类里面post方法 为什么???

    为什么会自动分布请求类中的get/post方法呢?有什么在自动识别?

    验证请求方式的get/post的执行

    #CBV视图
    from django.views import View
    from django.conf import settings
    class MyLogin(View):
        def get(self,request):
            print("from MyLogin get方法") 为什么会走get/post
            return render(request,'login.html')
        def post(self,request):
            return HttpResponse("from MyLogin post方法")

    CBV对应的路由层:url

       由于函数名加括号执行优先级最高,所以这一句话一写完会立刻执行as_view()方法

    1、从url入手分析这一现象的存在:分析as_view源码解析结果:

    分析步骤:

     点击view方法查看:

     点击view继承的父类dispatch方法

     再次查看源码部分内容分析:

    源码解析:

    @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返回什么 浏览器就会收到什么
    # 对象在查找属性或者方法的时候 你一定要默念 先从对象自己这里找  然后从产生对象的类里面找  最后类的父类依次往后
    return view

     通过源码发现url匹配关系可以变形成

    url(r'^login/',views.view)  # FBV和CBV在路由匹配上是一致的 都是url后面跟函数的内存地址

    2、当浏览器中输入login,会立刻触发view函数的运行

     第二部分分析源码:

    def dispatch(self, request, *args, **kwargs):
    # Try to dispatch to the right method; if a method doesn't exist,
    # defer to the error handler. Also defer to the error handler if the
    # request method isn't on the approved list.
    # 我们先以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方法
    # 源码中先通过判断请求方式是否符合默认的八个请求方法 然后通过反射获取到自定义类中的对应的方法执行
                                

    通过路由层url中的.re_view方法,解析源码分析得出实现get/post请求分发的原理,是什么请求就走什么方法

    Django settings 源码解析:

     前提:

    1、diango除了暴露给用户一个settings.py配置的文件之外,自己内部还有一个全局的配置文件(只是展示了部分信息的settnigs)。

    2、我们在使用配置文件的时候,可以直接导入暴露给用户的settings.py也可以使用django全局的配置问的文件

    需要导入的模块:from django.conf import settings

    点击settings 查看源码配置文件

    3、django的启动入口是manage.py

    分析为什么在settings配置文件中的变量名都是大写的?为什么写小写的就不行了呢?

    基于以上分析源码后,分析实现seettings的功能,受限变量名必须写大写

    import os
    import sys
    
    if __name__ == "__main__":
    # django在启动的时候 就会往全局的大字典中设置一个键值对  值是暴露给用户的配置文件的路径字符串
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.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)
    or 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'
    用户如果配置了就用用户的
    用户如果没有配置就用系统默认的
    其实本质就是利用字典的键存在就是替换的原理 实现了用户配置就用用户的用户没配置就用默认的
    """

     class settings 实现必须书写大写的精髓部分:

     继承的类分析:

    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')
                            

    settings = LazySettings()  # 单例模式 

     

    实现功能的核心代码块:

    作业:
      参考django settings源码 实现自己的项目也能够做到 用户配置了就用用户的 用户没有配置 就用全局的

    __init__.py文件下:

    import os
    import importlib
    from  lib.conf import global_settings
    
    class Settings(object):
        def __init__(self):
            # 先for循环获取全局配置文件中所有的变量名
            for name in dir(global_settings):
                # 判断是否是大写
                if name.isupper():
                    #给settings对象设置键值对
                    setattr(self,name,getattr(global_settings,name))
            path = os.environ.get('xxx')
            module = importlib.import_module(path)
            #再循环暴露给用户的文件中所有的变量名
            for name in dir(module):
                if name.isupper():
                    k=name
                    v=getattr(module,name)
                    setattr(self,k,v)
    settings=Settings()

    start.py文件

    import os
    import  sys
    
    BASE_DIR = os.path.dirname(__file__)
    sys.path.append(BASE_DIR)
    
    
    if __name__ == '__main__':
        # 在项目中的全局一个大字典
        os.environ.setdefault('xxx','conf.settings')
        from lib.conf import settings
        print(settings.NAME)

    Django模板层

      模板语法

    1、为模板传值

    只需要记两种特殊符号:
    {{  }}和 {% %}
    变量相关的用{{}},逻辑相关的用{%%}。

     两种给前端传值的区别

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

    # return render(request, 'reg.html', locals())

    <p>传函数名,会自动加括号调用该函数,前端展示的是函数调用之后的返回值:{{ index }}

    注意:如果函数需要参数的话  那么不好意思 模板语法不支持


    变量
    在Django的模板语法中按此语法使用{{变量名}}.
    当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号


    标签与过滤器
    Filters(过滤器)
    在Django的语法中,通过使用过滤器来改变变量的显示.

    过滤器的语法: {{ value|filter_name:参数 }}

    使用管道符"|"来应用过滤器。

    {#<h1>模板语法之标签:内部原理(会将|前面的当做第一个参数传入标签中)</h1>#}

    注意事项:

    1、过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
    2、过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
    3、过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
    4、'|'左右没有空格没有空格没有空格
    

    Django的模板语言中常用的内置过滤器有:

    default:如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值

     一些常用的过滤器的详解:

    length

    返回值的长度,作用于字符串和列表。

    {{ value|length }}

    返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.

    filesizeformat

    将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB''4.1 MB''102 bytes', 等等)。例如:

    {{ value|filesizeformat }}

    如果 value 是 123456789,输出将会是 117.7 MB。

    slice

    切片

    {{value|slice:"2:-1"}}

    date

    格式化

    {{ value|date:"Y-m-d H:i:s"}}

    safe

    Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义

    比如:

    value = "<a href='#'>点我</a>"

    {{ value|safe}}

    前后端取消转义

     也就意味着前端的html代码 并不单单只能在html文件中书写
        你也可以在后端先生成html代码 然后直接传递给前端(**)

    前端

      |safe

    后端

    from django.utils.safestring import mark_safe
    mark_safe("<a href='url'>xxx</a>")

    truncatechars

      如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

    参数:截断的字符数

    {{ value|truncatechars:9}}

    truncatewords

    在一定数量的字后截断字符串。

    {{ value|truncatewords:9}}

    cut

    移除value中所有的与给出的变量相同的字符串

    {{ value|cut:' ' }}

    如果value为'i love you',那么将输出'iloveyou'.

    join

    使用字符串连接列表,例如Python的str.join(list)

    timesince

    将日期格式设为自该日期起的时间(例如,“4天,6小时”)。

    采用一个可选参数,它是一个包含用作比较点的日期的变量(不带参数,比较点为现在)。

    例如,如果blog_date是表示2006年6月1日午夜的日期实例,并且comment_date是2006年6月1日08:00的日期实例,则以下将返回“8小时”:

    {{ blog_date|timesince:comment_date }}

    分钟是所使用的最小单位,对于相对于比较点的未来的任何日期,将返回“0分钟”。

    timeuntil

    似于timesince,除了它测量从现在开始直到给定日期或日期时间的时间。 例如,如果今天是2006年6月1日,

    而conference_date是保留2006年6月29日的日期实例,则{{ conference_date | timeuntil }}将返回“4周”。

    使用可选参数,它是一个包含用作比较点的日期(而不是现在)的变量。 如果from_date包含2006年6月22日,则以下内容将返回“1周”:

    {{ conference_date|timeuntil:from_date }}

    标签:逻辑相关 {%%}

    for循环可用的一些参数:

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

    if判断

    if,elif和else

     结合使用:

    if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

    with

    定义一个中间变量,多用于给一个复杂的变量起别名。

    注意等号左右不要加空格。

     针对字典形式的取值:

    自定义过滤器和标签

    适应场景:例如Django提供的过滤器或标签不能够处理一些特殊的数据时,可以自定义写

    使用注意事项:

    1、先在应用名下的文件夹中新建一个名字必须叫做templatetags文件夹(必须是这个名字)

    2、在该文件夹内新建一个任意名称的.py文件

    3、在该py文件中,必须先写以下两句代码

    from django import template
    register = template.Library()

     前端的使用:

     自定义标签

    总结:

    from django import template
    				
    register = template.Library()
    
    # 自定义过滤器
    @register.filter(name='mysum')
        def mysum(a,b)
    	retunr a + b
    			
    # 自定义标签
    @register.simple_tag(name='myplus')
        def myplus(a,b,c,d,e):
    	return None
    			
    # 自定义inclusion_tag
    @register.inclusion_tag('mytag.html')
    	def mytag(n):
    			...
    		# return {'l':l}
    	return locals()

     在html上使用需要先导入后使用

    {% load py文件名 %}
    {{ 2|mysum:1}}
    {% myplus 1 2 3 5 5 %}
    {% mytag 10 %}

    模板的继承与导入

    使用的场景:当多个HTML页面需要使用相同的HTML代码的时候,可以考虑使用继承

    搭页面:

    首先需要你在模板html代码中 通过block块儿划定后续想要修改的区域
       {%block content%}
       {%endblock%}

    一般情况下 模板html文件内应该有三块区域 css,content,js

    模板一般情况下
    应该至少有三个可以被修改的区域
    { % block
    css %}
    子页面自己的css代码
    { % endblock %}
    
    { % block
    content %}
    子页面自己的html代码
    { % endblock %}
    
    { % block
    js %}
    子页面自己的js代码
    { % endblock %} 

    实际应用到html:

     简单的结构介绍:

    模板的导入
    {% extends '模板的名字'%}
    {%block content%}
    修改模板中content区域的内容
        {{ block.super }}重新复用模板的html样式
            {%endblock%}
                
                
    模板的导入
        {% include '你想要导入的html文件名'%}
                

    模板的导入:关键字:include 路由分发:也是用这个关键字,联想记忆

    模型层的单表查询

    创建表:

    create_time = models.DateField()
    关键性的参数
    1.auto_now:每次操作数据 都会自动刷新当前操作的时间
    2.auto_now_add:在创建数据的时候 会自动将创建时间记录下来 后续的修改不会影响该字段

    简单创建一张表:

    创建表后记得更新表的迁移操作:两条命令

    编写测试脚本:

      在django中 你可以写一个单独测试某一个py文件的测试脚本 不需要再频繁的走web请求

     单表的操作: 增  删  改  查

    import os
    import sys
    
    if __name__ == '__main__':
        # django 在启动的时候 就会往全局的大字典一个键值对,值时暴露给用户的
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Djangoday54.settings")
    
        import  django
        django.setup()
    
        from app01 import models
        models.Book.objects.all()
        book_obj = models.Book.objects.create(title="百年孤独",price=199.99,create_time=2019-11-20)
        print(book_obj.title)
    
        # from datetime import datetime
        # ctime = datetime.now()
        # book_obj = models.Book(title='围城',price=200.99,create_time=ctime)
        # book_obj.save()
        #
        print(models.Book.objects.all())
        print(models.Book.objects.get(id=2)) # 自动查找到当前的数据主键字段
    
        # 改 update
        models.Book.objects.filter(pk=1).update(title='百年孤独')
        book_obj =models.Book.objects.get(pk=1)
        book_obj.price = 66.34
        book_obj.save()
    
        # 删除 delete()
        models.Book.objects.filter(pk=1).delete()
    单表的增删改查

      单表查询必会的13个方法:

    返回QuerySet对象的方法有

    all()

    filter()

    exclude()

    order_by()

    reverse()

    distinct()

    特殊的QuerySet

    values()       返回一个可迭代的字典序列

    values_list() 返回一个可迭代的元祖序列

    返回具体对象的

    get()

    first()

    last()

    返回布尔值的方法有:

    exists()

    返回数字的方法有

    count()

     < 1 > all(): 查询所有结果
        < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
        < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
        < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
        print(models.Book.objects.exclude(pk=1))  # 只要pk不是1的数据全部查询出来
    
        < 5 > order_by(*field): 对查询结果排序('-id') / ('price')
        print(models.Book.objects.order_by('price'))  # 默认是升序
        print(models.Book.objects.order_by('-price'))  # 加负号就是降序
    
        # < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
        # print(models.Book.objects.order_by('price').reverse())
        # < 7 > count(): 返回数据库中匹配查询(QuerySet)
        # print(models.Book.objects.count())  # 对查询出来的结果进行一个计数
        
        # < 8 > first(): 返回第一条记录
        # print(models.Book.objects.filter(pk=1).first())
        # < 9 > last(): 返回最后一条记录
        # print(models.Book.objects.all())
        # print(models.Book.objects.all().last())
    
        # < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
        # print(models.Book.objects.filter(pk=1000))
        # print(models.Book.objects.filter(pk=1000).exists())
    
        # < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
        # model的实例化对象,而是一个可迭代的字典序列
        # print(models.Book.objects.values('title','price'))  # 得到的结果是列表套字典
    
        # < 12 > values_list(*field): 它与values()
        # print(models.Book.objects.values_list('title','price'))  # 得到的结果是列表套元组
    
        # 非常相似,它返回的是一个元组序列,values返回的是一个字典序列
        # < 13 > distinct(): 从返回结果中剔除重复纪录
        """
        去重的前提是 一定要有完全重复的数据 才能去重
        """
        # print(models.Book.objects.filter(title='三国演义').distinct())
        # print(models.Book.objects.values('title','price','create_time').distinct())
    其他方法的使用

      

      





      

  • 相关阅读:
    WinForm多线程+委托防止界面假死
    C#中异步及winform中界面假死
    js如何判断当前文本的输入状态——中文输入法的那些坑
    数据库主键设计之思考
    node.js使用superagent实现模拟登陆功能(包含下载验证码功能)
    application.properties在Spring Boot项目中的位置
    ubuntu18.04安装chromium浏览器
    ubuntu 18.04安装mysql 8
    Spring Boot学习笔记——搭建一个最简单的hello world
    ubuntu 18.04安装jdk8和eclipse
  • 原文地址:https://www.cnblogs.com/Gaimo/p/11546390.html
Copyright © 2011-2022 走看看