9_18视图层某内部原理(fbv和cbv)与模板层

一。render内部原理。

  在render中往往需要返回三个参数,request,模板和一些键值对。

  键值对中存储的是需要对模板渲染的值。

  如果手动实现可以如下:

from django.template import Template,Context
def index(request):
    temp = Template('<h1>{{ user }}</h1>')
    con = Context({"user":{"name":'jason',"password":'123'}})
    res = temp.render(con)
    print(res)
    return HttpResponse(res)

   首先拿到模板,再用render对模板进行渲染,最后使用字符串的形式返回。

二。FBV和CBV

  FBV(function base view)

  CBV(class base view)

  一个是基于函数编写的视图,一个是基于类编写的视图。

  对于基于函数编写的就是运行其返回的值,也就是三个渲染模板函数产生的值。

  而基于类编写的,需要运行视图函数中的一个内置类函数产生的函数,本质是一个闭包函数。

  编写类函数:

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方法")        

  编写url:

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

  可以看到其中需要调用mylogin中运行自己编写的类中的as_view函数。然而这个函数是继承的VIew中的函数。

  as_view

  as_view是一个绑定类方法的函数。除了正常的异常处理之外,其内部有一个闭包函数,也就是说调用这个函数之后产生的结果就是这个view函数的返回值。

  当url匹配成功后,会调用view方法,在view内部返回的是一个使用自定义函数产生的的对象中的dispatch方法(继承父类View的方法)。

  也就说dispatch产生的值就是最终返回的值。也就是渲染的页面。dispatch中会首先判断你的请求是否是属于8个基本请求之一。如果是就通过这个字符串和自身定义的类产生的对象,getattr获取对应的函数,最后通过这个函数运行得到渲染的模板返回。

八种请求:
http_method_names =
['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

三。django中settings源码。

  对于django中的settings是提供给我们配置文件用的,除了大写的变量之外,其他变量都没有效果,所以其内部会经过独特的处理。

  其实,在django框架中有一个全局的配置文件,暴露给用户的settings是很小的一部分,其调用方法如下:

from django.conf import settings

  首先介绍os.environ。这相当于一个全局的字典,可以支持字典取值设置值的任何方法。其次介绍dir方法,dir可以将一个模块中的所有变量名取出。

  在django启动时,会直接运行manage.py文件,这个文件会先将暴露给用户的settings路径,以变量名:DJANGO_SETTINGS_MODULE为键,加入全局字典中。

  在settings方法内部就是一个单例模式,每当调用settings时,会返回一个对象LazySettings()

  在LazySettings()内部,首先从全局字典中获取暴露给用户的settings的字符串,将其传给settings方法进行配置。

  settings方法首先使用dir方法和for循环获取全局设置中的所有配置,如果是大写就添加到他产生的对象中,也就是调用模块时。

  接着再调用用户配置的settings,使用字符串调用模块。同样使用for循环。如果本来的设置中存在就覆盖其值,没有则新建。

  也就是说会优先使用用户的设置。

四。模板层之传递值。

  当我们使用视图函数向模板传值时,一般都使用字典的方式。

def index(request):
    return render(requset,'html',{'名字‘:’数据‘})

  然而当有多个值的时侯,单个传值显然很麻烦,通过locals()方法,可以将该函数中的所有参数传递给前端:

def index(request):
  return render(request,'reg.html',locals())

  虽然locals()方法可以一劳永逸,但是会浪费资源,会传递前端不要的参数。

  传入的值如果数python的数据类型几乎都可以被渲染,但是也有特殊的:

  1.函数。

  如果传函数名,会自动加括号调用该函数,前端展示的是函数调用之后的返回值。

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

  2.类。

  如果将类实例化对象传给前端,会将该对象的内存地址传入,前端页面可以通过该对象名点出其中的函数方法和变量。

  其中的函数也不支持传参。

  模板语法:

  {{}} 变量相关。

  {%%}语法相关。

五。模板语法过滤器。

  过滤器的固定语法是:

{{ 变量名|过滤器名 }}

  其内部原理是,将|前面的变量名当成过滤器的第一个参数传入。

@register.filter(is_safe=False)
def length(value):
    """Returns the length of the value - useful for lists."""
    try:
        return len(value)
    except (ValueError, TypeError):
        return 0

  如果不支持该过滤器,会返回0

 1。{{ l|length }}

  统计l的长度。

  2。{{ ss|default:'当|左边的变量为空就会返回|右边的值' }}

  如果ss存在,则返回ss,如果为空则返回default,如果ss不存在也返回他,和get很像。

  3。{{ file_size|filesizeformat }}

  将file_size转换成文件大小。

  4。{{ info|truncatewords:3 }}

  按照空格将info文字进行截断,3是截断的个数。

  5。{{ info|truncatechars:6 }}

  按照字符截取info,点也算,也就是至少传入3。

  6。{{ xxx|safe }}

  一般的,xxx字符串传入前端后,直接以字符串的形式传入,但是加上safe之后,就会将xxx按照原来的意思进行输入,如果该字符是页面元素,会显示页面元素。

  后端可以取消这个机制:

from django.utils.safestring import mark_safe
zzz=make_safe('内容')

  7.{{ ctime|date:'Y-m-d H-i-s' }}

  如果后端传来的ctime是一个时间类型的数据,那么可以通过过滤器date进行渲染。

  8.{{ n|add:100 }}

  将n数字加100,如果是字符串,则拼接字符串。

  9.{{ l|slice:'0:5:2' }}

  将1切片,故头不顾尾,支持步长

六。模板层之标签。

  标签也就是逻辑相关的操作,使用{% %}

  1.forloop。

  在for循环中,这个标签可以记录for循环的一些值:

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

  如图:

 

 

   2.{%empty%}

  当for 循环为空,则执行这个标签下的方法。

  3.if判断:

{% if '' %}
<p>xxx条件为true</p>
    {% else %}
    <p>xxx条件为false</p>
{% endif %}

  4.点。

  django模板语法在取值的时候 统一使用句点符。如:

{ l.6.3.name }

  5.{%with 数据 as 别名%}

  可以通过这个标签给数据取别名,这样可以方便操作。在with中就可以使用该别名。

    {% with l.6.3.name as ttt %}  
        {{ ttt }}
        {{ l.6.3.name }}
    {% endwith %}

  6.for循环中字典的三个方法:

{% for foo in d.keys %}
    <p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}
    <p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}
    <p>{{ foo }}</p>
{% endfor %}

七。自定义过滤器与标签。

  自定义的东西需要遵循下面三个步骤:

  1.必须在你的应用下新建一个名为templatetags文件夹

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

  3.在该py文件中固定先写下面两句代码

    from django import template

    register = template.Library()

  然后就可以在这个文件下面编写字节的过滤器了:

@register.filter(name='baby')
def index(a,b):
    # 该过滤器只做一个加法运算  是|add简易版本
    return a + b

  定义的时候需要给它取个别名,然后要阿紫网页中调用该过滤器。

{% load mytag %}
{{ 123|baby:1}}

  其中mytag是template下的文件名,baby是起的名字。

  注意,自定义guolq只能指定两个形参,但是第二个参数可以是一个列表。

  自定义标签

  标签的定义方法和guolvq差不多:

@register.simple_tag(name='jason')
def xxx(a,b,c,year):
    return '%s?%s|%s{%s'%(a,b,c,year)

  但是标签支持传入多个参数,标签的使用:

支持传多个参数  参数与参数之间 空格隔开即可、
{% load mytag %}
{% jason 1 2 3 year=2 %}

  也支持关键字传参。

  自定义inclusion_tag

  这个工作原理是接受用户传入的参数,然后根据参数渲染出一个页面,再返回到调用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}

  它需要指定一个页面,这个页面是要被调用的页面,会接受这个函数返回的值。

 

   调用:

{% load mytag %}
{% bigplus 5 %}

  应用场景:

  可以定义一个多次运用的页面,可以反复调用。

八。模板的继承和导入。

  继承:

  当多个页面整体的样式都大差不差的情况下 可以设置一个模板文件。

  在该模板文件中 使用block块划分多个预期。

  之后子版在使用模板的时候 可以通过block块的名字 来选定到底需要修改哪一部分区域

  也就是说,母模板中可以将需要改变的地方通过{% block css%}  {% endblock%}划分页面。

{% block css %}
    子页面自己的css代码
{% endblock %}            
{% block content %}
    子页面自己的html代码
{% endblock %}
{% block js %}
    子页面自己的js代码
{% endblock %}

  这个名字是自己定义的。

  在其他页面可以继承这个母模板进行复用:

# 模板的继承  使用方式
{% extends 'home.html' %}

{% block css %}
    <style>
        h1 {
            color: red;
        }
    </style>
{% endblock %}

  通过{{ block.super}} 也可以获得目标签该区域的元素

  一般情况下 模板上的block越多 页面的可扩展性就越强。

  模板的导入:

{% include 'beautiful.html' %}

  将一个静态的页面,通过导入的方式加入模板。

 九。模型层。

  1.单表操作。

  create_time = models.DateField()

  创建时间的这个参数有关键性的参数。

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

  增:

  方法1:

book_obj = models.Book.objects.\
create(title='三国',price=19.99,create_time='2019-11-11')

   方法2:

    方式2:对象点save()方法
    from datetime import datetime
    ctime = datetime.now()
    book_obj = models.Book(title='',price=96.66,create_time=ctime)
    book_obj.save()

  查:

models.Book.objects.all()
#查询所有的数据
models.Book.objects.get(id=1)
#按照id查询
models.Book.objects.get(pk=1)
#自动按照主键查询

  改:

    1.update
    models.Book.objects.filter(pk=1).update(title='三国演义')
    2.对象.save()
    book_obj = models.Book.objects.get(pk=1)
    book_obj.price = 666.66
    book_obj.save()

  删:

 删除  delete()
 models.Book.objects.filter(pk=2).delete()

  其他的函数方法:

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

 

补充:

  1.如果一个类中的函数时绑定类方法,而使用对象调用,会获取对象的类,当成第一个参数传入。

  2。通过字符串导入模块的方法:

import importlib
mod = importlib.import_module(从哪个模块中,’所调用的模块的字符串‘)

   3.在django中可以写一个单独的test模块进行测试。:

import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")
    import django
    django.setup()
#下面导入模块进行测试。

 

posted on 2019-09-18 22:21  一只萌萌哒的提莫  阅读(215)  评论(0编辑  收藏  举报