Django视图层与模板层

Django视图层与模板层

视图层

JsonResponse

向前端返回一个json格式字符串的两种方式

方式一:

import json

def my_view(request):
    data = ['tank', 'sean', 'jason']
    return HttpResponse(json.dumps(data))

方式二:

from django.http import JsonResponse

def my_view(request):
    data = ['tank', 'sean', 'jason']
    return JsonResponse(data, safe=False)
	# 默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象
form表单上传文件

前端

<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="myfile">
    <input type="submit">
</form>

后端

def homes(request):
    if request.method == 'POST':
        # 获取用户上传的文件数据
        print(request.FILES)
        file_obj = request.FILES.get('myfile')
        print(file_obj.name)
        with open(file_obj.name, 'wb')as f:
            for line in file_obj.chunks():
                f.write(line)

    return render(request, 'home.html')
render原理

需要导入两个模块Template,Context

from django.template import Template,Context

def ab_render(request):
    temp = Template("<h1>{{ user_dic }}{{ user_dic.username }}{{ user_dic.password }}</h1>")
    user_dic = Context({'user_dic': {'username': 'jason', 'password': '123'}})
    res = temp.render(user_dic)
    return HttpResponse(res)
FBV和CBV

Django的视图层由两种形式构成:FBV和CBV

  1. FBV(Function base view)基于函数的的视图,之前一直都是FBV
  2. CBV(Class base view)基于类的视图

CBV的基本写法

urls.py

from app01 import views

urlpatterns = [
    # CBV路由配置
    url(r'^login', views.MyLogin.as_view()),
    # 必须调用类下的方法as_view
]

views.py

class MyLogin(View):
        def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        if name == 'egon' and pwd == '123':
            res = '登录成功'
        else:
            res = '用户名或密码错误'
        return HttpResponse(res)

login.html

<form action="" method="post">
    <p>username:<input type="text" name="name"></p>
    <p>password:<input type="text" name="pwd"></p>
    <input type="submit">
</form>

login提交get请求会自动执行MyLogin中的get方法,提交post请求会自动执行MyLogin中的post方法,为什么能够针对不同的请求能够自动执行对应的方法

CBV的原理

在对应关系中:url(r'^login', views.MyLogin.as_view())

as_view

  • 要么是类中定义的方法(普通函数)@staticmethod

  • 要么是类中定义的绑定类的方法@classmethod

看源码得知,是绑定给类的方法


Django配置文件原理

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

from django.conf import global_settings, settings

点进settings可以看到

settings = LazySettings() # 这是个基于模块的单例
# 而 LazySettings()很明显是调用了一个类或函数

点进LazySettings可以看到

针对在哪里设置了"DJANGO_SETTINGS_MODULE"这个键值对,点进manage.py

然后在点进LazySettings类中的Settings可以看到

这里有个小方法importlib

有两个py文件,a和b
b在文件夹conf下,写有name = 'jason'

在a中想要获取这个名字可以有两种方法

第一种

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

第二种

import importlib

res = 'conf.b'
md = importlib.import_module(res)
# 该方法最小单位是模块,不能是模块里面的单个名字
print(md.name)  # jason

有助于以后看源码


模板层

模版语法符号:

{{ }}		变量相关
{% %}		逻辑相关
模版语法之传值取值

Python基本数据类型全部支持传给HTML页面(函数和类也可以传)

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

后端给HTML页面传值的两种方式

  1. 指名道姓的传
# 方式一
return render(request, 'index.html', {'n': 11, 'f': 11.11, 's': 'hello world'})
  1. locals()
# 方式二   locals会将当前名称空间中所有的变量名全部传给HTML页面
return render(request, 'index.html', locals())

HTML页面中,如何获取到后端传递过来的数据

{{ 变量名 }} 比如:{{ n }} {{ f }} {{ s }}

取值

Django模版语法取值,使用句点符,索引,键

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

模版语法之过滤器(变量相关)

过滤器一个 | ,管道符

左边的会当做过滤器的第一个参数 | 过滤器右边的会当做第二个参数

|length		求数据长度
{{ s|length }}		11

|add	加法运算
{{ n|add:10 }}  {{ s|add:'DSB' }}	21	hello worldDSB

|default	默认值(判断值是否为空)
{{ b|default:'这个b布尔值是True' }}	True

|truncatechars	截取字符
{{ s|truncatechars:8 }}		hello...

|truncatewords	截取单词
{{ s|truncatewords:8 }}		hello world

|filesizeformat	文件大小
{{ file_size|filesizeformat }}	2.8G

|slice	切片操作
{{ s|slice:'0:2' }}、{{ s|slice:"0:8:2" }}	he、hlow

|date	日期格式化
{{ ddd|date:'Y-m-d' }}		2020-01-07

|safe	转义
{{ res|safe }}	hello(一级标签hello)
转义在后端也可以实现
from django.utils.safestring import mark_safe
res2 = mark_safe("<h1>hello</h1>")

{{ res2 }}	hello(一级标签hello)

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


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

for 循环和if判断

{% for foo in l %}
    {% if forloop.first %}
        <p>这是第一次</p>
        {% elif forloop.last %}
        <p>这是最后一次</p>
        {% else %}
        <p>{{ foo }}</p>
    {% endif %}
	{% empty %}
    <p>for循环的对象内部没有值</p>
{% endfor %}

前端的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 %}

当一个值获取的步骤非常繁琐,但是又需要在很多地方需要用到,我们可以起别名

{% with d.hobby.1.username.1 as eg %}
	 <p>{{ eg }}</p>	<!--只能在with体内用-->>
{% endwith %}

自定义过滤器、标签和inclusion_tag

先完成以下前期准备工作

  1. 在应用名下新建一个名字必须叫templatetags文件夹
  2. 在该文件夹内新建一个任意名称的py文件(eg:mytag)
  3. 在该文件内 必须先写以下两句代码
from django.template import Library

register = Library()

自定义过滤器

# 自定义过滤器
@register.filter(name='my_sum')
def index(a, b):
    return a + b
<p>自定义过滤器的使用</p>
{% load mytag %}
<p>{{ 10|my_sum:90 }}</p>

100

<p>自定义的过滤器可以在逻辑语句中使用而自定义标签不可以</p>
{% if 10|my_sum:100 %}
    <p>条件成立</p>
{% endif %}

自定义标签

# 自定义标签
@register.simple_tag(name='my_baby')
def xxx(a, b, c, d):
    return "%s?%s?%s?%s" % (a, b, c, d)
<p>自定义标签的使用</p>
{% load mytag %}
<p>{% my_baby 1 2 3 "hello world" %}</p>

1?2?3?hello world

自定义inclusion_tag

# 自定义inclusion_tag
@register.inclusion_tag('demo.html', name='myinc')
def index1(n):
    l = []
    for i in range(n):
        l.append(i)
    # 将列表传递给demo.html
    return {'data': l}
<p>自定义inclusion_tag的使用</p>
{% load mytag %}
{% myinc 7 %}
<!--demo.html-->
<ul>
    {% for foo in data %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>

总结:页面上使用他们,统一先导入load

{% load mytag %}

模版的继承

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

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

{% block content %}
{% endblock %}

子页面中先导入整个模版

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

通常情况下,模版页面应该有三块区域

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

例子:

urls.py

    # 模版的导入
    url(r'^mdzz/', views.mdzz),
    url(r'^loginn/', views.loginn),
    url(r'^reg/', views.register),

views.py

def mdzz(request):
    return render(request, 'mdzz.html')

def loginn(request):
    return render(request, 'loginn.html')

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

mdzz.html

<!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>
    {% load static %}
    <link rel="stylesheet" href="{% static '/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static '/bootstrap-3.3.7-dist/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="/mdzz" class="list-group-item active">
                首页
              </a>
              <a href="/reg" class="list-group-item">注册</a>
              <a href="/loginn" class="list-group-item">登录</a>
              <a href="#" class="list-group-item">修改密码</a>
              <a href="#" 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">
            {% block content %}
                <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>

            {% endblock %}
          </div>
</div>

        </div>
    </div>
</div>
</body>
</html>

loginn.html

{% extends 'mdzz.html' %}

{% block content %}
<h2 class="text-center">登录页面</h2>
    <form action="">
    <p>username:
        <input type="text" class="form-control">
    </p>
    <p>password:
        <input type="text" class="form-control">
    </p>
        <input type="submit" class="btn btn-success" value="登录">
    </form>
    {{ block.super }}

{% endblock %}

reg.html

{% extends 'mdzz.html' %}

{% block content %}
<h2 class="text-center">注册页面</h2>
    <form action="">
    <p>username:
        <input type="text" class="form-control">
    </p>
    <p>password:
        <input type="text" class="form-control">
    </p>
        <input type="submit" class="btn btn-info" value="注册">
    </form>
    {{ block.super }}
{% endblock %}

模块的block块越多,可扩展性越高

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

    {{ block.super }}
模版的导入

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

{% include 'left.html' %}
基于django settings源码实现项目配置文件的 插拔式设计

自己实现一个类似于Django配置文件

用户可管理的配置文件(settings)

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

项目默认的配置文件(global_settings)

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

启动文件

import os, 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)

__init__.py

import importlib, 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)
                setattr(self, k, v)
        
        # 先获取暴露给用户的配置文件的字符串路径
        module_path = os.environ.get('xxx')
        # 利用importlib模块导入settings文件
        md = importlib.import_module(module_path)
        
        # 同上
        for name in dir(md):
            # 判断变量名是否是大写
            if name.isupper():
                # 将键值对设置给对象
                k = name    # NAME
                v = getattr(md, name)
                setattr(self, k, v)

settings = Settings()
原文地址:https://www.cnblogs.com/YGZICO/p/12198732.html