1. FBV与CBV
FBV(基于函数的视图)
CBV(基于类的视图)
Python 是一个门面向对象的编程语言。如果我们只用函数来编写视图函数,
那么就会造成很多面向对象的优点无法利用起来,比如说封装、继承、多态等
1.1 FBV
FBV 基于函数的视图
在views.py视图中中定义函数来处理用户请求,
函数中再定义如果是GET请求怎么处理,POST请求怎么处理...
0. 新建一个项目,解决template文件夹路径错误,注释中间件.
1. 项目路由层
2. app01视图函数
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^register/', views.register),
]
from django.shortcuts import render, HttpResponse, redirect
def register(request):
return HttpResponse('index页面')
1.2 CBV
CBV 基于类的视图
体现了Python面向对象这一语言特性。CBV 是通过类的方式来编写视图函数.
这相比较于函数,更能利用面向对象中多态的特性,因此更容易将项目中比较通用的功能抽象出来。
* urls.py文件中CBV的书写方式 类名.as_view() 方式映射,
定义的类需要继承 View 类,
定义的方法按照固定样式,View类中支持以下方法:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
CBV的特点:能根据不同的请求方式匹配对应的方法执行。
0. 项目路由层
1. app01视图函数
2. template 目录下创建 login.html
url(r'^login/', views.Login.as_view())
from django.views import View
class Login(View):
def get(self, request):
return render(request, 'login.html')
def post(self, request):
return HttpResponse('Login页面 POST 请求')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登入页面</title>
</head>
<body>
<div>
<form action="" method="post">
<input type="submit">
</form>
</div>
</body>
</html>
3. 在浏览器中输入: 127.0.0.1:8000/login
4. 点提交
1.3 CBV源码解析
1.启动程序时
函数名,方法名加括号执行优先级最高。
在启动 Django 时就会执行 views.mylogin.as_view()
Login是类名,类使用.as_view()
查看源代码可以得知 结果就是 views.view
url('^login/', views.Login.as_view())
变形为 url('^login/', views.view),
CBV和FBV在路由上本质是一样的,都是路由对应函数内置地址。
在输入127.0.0.1:8000/login时触发 views.view
2.请求来的时候
getattr 反射:通过字符串来操作对象的属性或者方法
getattr(自己写的类对象,'小写的请求方式get/post',当找不这个小写的请求时才使用第三个参数)
不要修改源码,出现bug难查找。
在查看源码的时候一定要时刻提醒自己面对对象属性方法的查找顺序。
在查看源码时看到self.东西,一定要问自己当前这个self是谁
1. 先从自己的对象中找
2. 再去产生对象的类中查找
3. 父类中查找
class View(object):
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
for key, value in six.iteritems(kwargs):
setattr(self, key, value)
@classonlymethod
def as_view(cls, **initkwargs):
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs)
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)
"""
其他的不看了
"""
return view
def dispatch(self, request, *args, **kwargs):
"""
request.method.lower() 获取请求方式 转小写
判断 请求是否在 http方法列表中
如果 存在 则取 去自己写的类总找对应请求名字的方法 赋值 给 handler,
自己没有写这个请求的方法就抛出异常
如果不存在,就将抛出异常的代码 赋值 给 handler
执行handler handler要么是自己写的请求方法 要么是请求不存在http方法列表中报错
"""
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
"""
其他的不看了
"""
2. 模板层
2.1 模板语法
模板语法的书写方法:
{{ 变量名 }} 变量相关
{% %} 逻辑相关 for循环等
基本的数据类型都可以传递给前端。
模板语法内部会自动判断当前的变量(函数名, 类名)是否可以加括号调用,
如果可以就会自定加括号执行。
传递函数名会自动加括号进行调用,传递的是返回值.
传递类名的时候也会自动加括号实例化,传递的是对象.
* 模板语法不支持函数传递额外的参数,如果函数带参数则不会执行这条模板语法语句。
Django模板语法的取值格式:
1. 句点符 .键取值
2. 可以点索引
3. 两者混合使用
2.2 测试环境
1. 路由层
url('^index/', views.index)
2. 视图层
def index(request):
return render(request, 'index.html')
3.前端页面
templates目录下创建index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法测试</title>
</head>
<body>
<h1>模板语法测试</h1>
</body>
</html>
2.3 基本数据类型传递
模板语法可以传入后端Python数据类型
整型, 浮点型 字符串, 列表, 元组, 字典, 集合, 布尔值
def index(request):
int_ = 1
float_ = 1.1
str_ = 'hello'
list_ = [1, 2]
tuple_ = (1, 2)
dict_ = {'k1': 'v1'}
set_ = {1, 2}
bool_ = True
print(locals())
return render(request, 'index.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法测试</title>
</head>
<body>
<h1>模板语法测试</h1>
{{ int_ }}
{{ float_ }}
{{ str_ }}
{{ list_ }}
{{ tuple_ }}
{{ dict_ }}
{{ set_ }}
{{ bool_ }}
</body>
</html>
.键取值
索引取值
值可以使用方法.
def index(request):
str_ = 'hello'
list_ = [1, 2]
tuple_ = (1, 2)
dict_ = {'k1': 'v1', 'k2': 'v2'}
dir1 = {'name': ['you', {'小名': ['二狗子', '狗剩']}]}
print(locals())
return render(request, 'index.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法测试</title>
</head>
<body>
<h1>模板语法测试</h1>
<p> {{ str_.0 }} {{ str_.1 }} </p>
<p> {{ list_.0 }} </p>
<p> {{ tuple_.0 }} </p>
<p> {{ dict_.keys }} {{ dict_.values }} {{ dict_.k1 }}</p>
<p> {{ dir1.name.0 }} </p>
<p> {{ dir1.name.1.小名 }}</p>
</body>
</html>
2.4 传递函数结果
def index(request):
def func1():
return 'func1 的返回值'
print(locals())
return render(request, 'index.html', locals())
<p> {{ func1 }} </p>
函数携带参数的话,模块语法没有办法提供参数给函数,就直接不执行了.
def index(request):
class Myclass1(object):
def get_self(self):
print(0)
return self
@staticmethod
def func():
print(1)
return '静态方法'
@classmethod
def get_class(cls):
print(2)
return cls
print(locals())
return render(request, 'index.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法测试</title>
</head>
<body>
<h1>模板语法测试</h1>
<p> {{ Myclass1.get_self }} </p>
<p> {{ Myclass1.func }} </p>
<p> {{ Myclass1.get_class }} </p>
</body>
</html>
只有是函数名称空间中名称都会被 locals()查出来,传到前端页面中.
3. 过滤器
过滤器是模板语法的内置方法。
Django内置有60多个过滤器。
过滤器的基本语法:
{{ 数据|过滤器:参数}}
自定义的过滤器的参数最多就2个
3.1 常见过滤器
1. length 统计长度 (内部源码len())
2. default 默认值 第一个数据布尔值为True就展示第一个数据的值,否则就展示冒号后面的值。
3. filesizeformat 文件大小,将字节进行对应的单位换算。
4. date 日期格式。
5. slice 切片操作, 支持步长。
6. truncatechars 切取字符,三个点就占三个字符,设置大于3,不然就看到三个点。
7. truncatewords 按空格切取单词,不不包含三个点。
8. cut 移除特定的字符
9. join 拼接操作
10. add 加法
11. safe 转义
1. 统计长度
length 统计长度 (内部源码len())。
str_ = '1234'
<p>长度统计: {{ str_|length }} </p>
2.默认值
default 默认值 |前面的数据 布尔值为True 就展示第一个数据的值,否则就展示default冒号后面的值。
bool_0 = True
bool_1 = False
<p> {{ bool_0|default:'前面的值为True 我就不打印' }} </p>
<p> {{ bool_1|default:'前面的值为False 我不打印' }} </p>
3.文件大小
filesizeformat 文件大小,将字节进行对应的单位换算。
file_size1 = 1000000
file_size2 = 56565265
<p>{{ file_size1|filesizeformat }}</p>
<p>{{ file_size2|filesizeformat }}</p>
4.日期格式
格式设置 date:'Y-m-d H:i:s' 配合datetime使用
import datetime
now_time = datetime.datetime.now()
<p>现在时间:{{ current_time }}</p>
<p>格式设置:{{ current_time|date:'Y-m-d H:i:s' }}</p>
5.切片操作
slice切片操作, 支持步长。
list_ = ['qz', 'qq', 'cc', 'dd']
<p>切片操作:{{ list_|slice:'0:3:2' }}</p>
6.切取字符
truncatechars 切取字符,默认有三个点占三个字符,设置大于3,不然就看到三个点。
info = "abcdefghijklmnopqrst"
<p>窃取操作:{{ info|truncatechars:3 }}</p>
<p>窃取操作:{{ info|truncatechars:6 }}</p>
7.切取单词
truncatewords:x 按空格取分单词,切x个. 末尾有三个点。
msg = 'hao hao xue xi ha ha'
<p>切取单词:{{ egl|truncatewords:3 }}</p>
8.移除特定的字符
cut 移除特定的字符
msg = 'hao hao xue xi ha ha'
<p>移除特定字符:{{ egl|cut:' ' }}</p>
<p>移除特定字符:{{ egl|cut:'cao' }}</p>
9.拼接操作
join 拼接操作 每个元素添加字符
(* 只能是字符串做拼接)
msg = 'hao hao xue xi ha ha'
list_ = ['qz', 'qq', 'cc', 'dd']
<p>拼接操作:{{ msg|join:'---' }}</p>
<p>拼接操作:{{ list_|join:'---' }}</p>
10.加法
add 数字相加, 字符串拼接,否则 ' '空字符串。
str1 = '100'
str2 = 'aaa'
<p>加法运算:{{ str1|add:100 }}</p>
<p>加法拼接:{{ str2|add:s3}}</p>
11.前端转义
让前端执行转义。
h1 = '<h1>xxx</h1>'
<p>前端转义:{{ h1|safe }}</p>
后端转义:
以后在写全栈项目的时候,前端页面不一定要在前端页面书写,
也可以在后端写好,然后传递给前端页面,需要使用 mark_safe模块.
from django.utils.safestring import mark_safe('html代码')
res = mark_safe('html代码')
from django.utils.safestring import mark_safe
res = mark_safe('<h1>xxx</h1>')
<p>转义:{{ res }}</p>
4. 标签
{% 开始 %}
{% 结束 %}
4.1 for循环
{% for 变量 in 值 %}
{{循环体}}
{% endfor %}
list_ = ['aa', 'bb', 'cc', 'dd', 'dd']
{% for i in list_ %}
<p> {{ i }} </p>
{% endfor %}
4.2 forloop 参数
forloop 一个排序信息的字典
forloop.字典中的键取到值.
# forloop 参数
{% for foo in list_ %}
<p> {{ forloop }} </p>
{% endfor %}
{% for foo in list_ %}
<p>
{{ forloop.counter0 }} {{ forloop.counter }}
{{ forloop.revcounter0 }} {{ forloop.revcounter }}
{{ forloop.first }} {{ forloop.last }}
</p>
{% endfor %}
4.3 if判断
{% if判断语句 %}
if表达式为真执行的代码块
{% elif num == 10 %}
if表达式为真执行的代码块
{% else %}
所有条件都不满足执行的代码块
{% endif %}
num = 18
{% if num >= 18 %}
<p>成年了</p>
{% elif num < 18 %}
<p>未成年</p>
{% else %}
<p>年龄写错了</p>
{% endif %}
4.4 for 与 if 混用
{% for 变量 in 值 %}
{% iif判断语句 %}
if表达式为真执行的代码块
{% elif forloop.last %}
if表达式为真执行的代码块
{% endif %}
{% endfor %}
list_ = ['aa', 'bb', 'cc', 'dd', 'dd']
<!--下面写测试的模板语法-->
{% for i in list_ %}
{% if forloop.first %}
<p> 第一个值: {{ i}} </p>
{% elif forloop.last %}
<p> 最后一个值: {{ i }} </p>
{% endif %}
{% endfor %}
4.5 empty
for循环的可迭代对象为空时执行。
list_ = [1, 2]
{% for i in list_ %}
<p> {{ i }} </p>
{% endfor %}
<empty>
<p>3</p>
</empty>
4.6 for遍历字典
for 变量字典 默认只能拿到键
模板语法中可
字典可以使用.keys 获取所有的键
字典可以使用.values 获取所有的值
字典可以使用.items 获取键值对
键.
dict_ = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
{% for i in dict_.keys %}
<p> {{ i }} </p>
{% endfor %}
{% for i in dict_.values %}
<p> {{ i }} </p>
{% endfor %}
{% for i in dict_.items %}
<p> {{ i }} </p>
{% endfor %}
4.7 with起别名
在with语法内可以通过as起别名,一个别名代替一个模板语法取值语句。
别名快速的到前面复杂的模板语法中取值。
{% with 取值表达式 as 别名 %}
{{别名}}
{% withend %}
dict_ = {'name': ['you', {'小名': ['二狗子', '狗剩']}]}
<p>{{ dict_.name.1.小名.1}}</p>
{% with dict_.name.1.小名.1 as yourname %}
<p>{{ yourname }}</p>
<p>{{ yourname }}</p>
{% endwith %}
5. 自定义模板语法
过滤器、标签、inclusion_tag
必须步骤:
1.在app应用下创建一个名字叫templatetags文件夹。
2.在该文件夹内创建一个任意名称的.py文件
3.在该py文件内必须写下两个语句
from django import template
register = template.Library()
4. 前端先使用{% load 自动模板语法文件的名字 %}
5. {{ |name指定名字 }} 中 使用
0. 在app01 下创建templatetags文件夹
1. 在templatetags文件夹创建mytag.py
2. mytag.py文件内容:
from django import template
register = template.Library()
5.1 过滤器
* 自定义的过滤器函数最多只能有两个参数
from django import template
register = template.Library()
@register.filter(name='my_filter')
def my_filter(num):
if num >= 18:
msg = '成年人'
elif num < 18:
msg = '未成年'
else:
raise '请提供数据类型的数据!'
return msg
def index(request):
num = 1
return render(request, 'index.html', locals())
{% load my_delimit %}
<p> {{ num|my_filter }}</p>
自定义过滤器的函数只能有两个参数.
@register.filter(name='my_sum')
def my_sum(num1, num2):
return num1 + num2
<p> {{ num|my_sum:2 }}</p>
5.2 标签
可以接受任意个参数,参数之间用空格分隔开。
类似于自定义函数。
@register.simple_tag(name='my_sum2')
def my_sum2(num1, num2, num3, num4):
return num1+num2+num3+num4
{% load my_delimit %}
<p> {% my_sum2 num1 2 3 4 %}</p>
5.3 inclusion_tag
先定义一个方法,方法中指定一个模板页面.
在页面上调用该方法(可以传值)生成一些数据然后传递给模板页面.
之后将模板页面中渲染好的结果放到调用的位置
@register.inclusion_tag('模板页面.html')
@register.inclusion_tag('模板页面.html')
def my_item(n):
data = ['第{}项'.format(i) for i in range(n)]
将函数的名称空间传递给 前端页面
return locals()
['第{}项'.format(i) for i in range(n)]
列表生成器
['第1项', '第2项', ...]
<ul>
{% for i in data %}
<li>{{ i }}</li>
{% endfor %}
</ul>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法测试</title>
</head>
<body>
<h1>模板语法测试</h1>
{% load my_delimit %}
{% my_item 5 %}
</body>
</html>
当html页面某一个地方需要参数才能够动态的渲染出来,
并在在多个页面上都需要使用到该局部,那么将该局部页面作为inclusion_tag形式。
6. 继承模板
很多的网站页面整体都大差不差,只是某一些局部在做变化.
那么相同的地方就可以使用同提个模板,不同的地方在稍稍修改.
模板页面 models.html
{% block 区域的名字 %}
被替换的区域
{% endblock %}
子页面 xxx.html
{% extends 'models.html' %} 继承模板页面
{% block 区域的名字 %} 引用
写新的代码替换
{% endblock %}
一般情况下会留有三块可以被修改的区域。
1. css区域
2. html区域
3. js 区域
模板页面上划定的区域多,拓展性就高.(如果太多也没必要)
每一个子页面都可以有自己独立的css代码html代码js代码。
{% block css %}
被替换的区域
{% endblock %}
{% block html %}
被替换的区域
{% endblock %}
{% block js %}
被替换的区域
{% endblock %}
7. 继承模板案例
7.1 路由层
项目下的urls.py 写路由和视图函数的对应关系.
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^register/', views.register),
url(r'^login/', views.login),
url(r'^home/', views.home)
]
7.2 视图层
app01 应用下views.py 写视图函数.
from django.shortcuts import render, HttpResponse, redirect
def home(request):
return render(request, 'home.html')
def register(request):
return render(request, 'register.html')
def login(request):
return render(request, 'login.html')
7.3 模板页面
home主页,也是模板页面
设置不继承的区域.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
{% block css %}
{% endblock %}
</head>
<body>
<div>
<div>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<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="#">全栈开发</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">首页<span class="sr-only">(current)</span></a></li>
<li><a href="#">我的笔记</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">学习链接<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Python</a></li>
<li><a href="#">前端</a></li>
<li><a href="#">MySQL</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">博客园</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">CSND</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="在这看查询">
</div>
<button type="submit" class="btn btn-default">搜索</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">收藏本页</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">状态选择<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#"></a></li>
<li><a href="#">隐身</a></li>
<li><a href="#">免打扰</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<ul class="list-group">
<li class="list-group-item list-group-item-danger"><a href="/home/">主页</a></li>
<li class="list-group-item list-group-item-success"><a href="/register/">注册</a></li>
<li class="list-group-item list-group-item-info"><a href="/login/">登入</a></li>
</ul>
</div>
<div class="col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">请看这里</h3>
</div>
<div class="panel-body">
{% block content %}
<div class="jumbotron">
<h1>学习入口</h1>
<p>欢迎你的登入!</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">进入</a></p>
</div>
{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
<script>
{% block js %}
alert('主页面')
{% endblock %}
</script>
</body>
</html>
7.4 继承模板
0. register.html 中继承home.html页面.
1. login.html 中继承home.html页面.
{% extends 'home.html' %}
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
2. 在浏览器中 127.0.0.1:8000/home
3. 在浏览器中 127.0.0.1:8000/register
4. 在浏览器中 127.0.0.1:8000/login
* 修改模板的栅格 1 - 11 所有是有这个模板的页面都会跟着改变.
7.5 注册页面
{% extends 'home.html' %}
{% block css %}
<style>
h1 {
color: gold;
}
</style>
{% endblock %}
{% block content %}
<div>
<form action="" method="post">
<h1 class="text-center">注册页面</h1>
<p>用户名称:
<input type="text" name="username" class="form-control">
</p>
<p>用户密码:
<input type="password" name="password" class="form-control">
</p>
<input type="submit" value="注册" class="btn btn-block btn-info">
</form>
</div>
{% endblock %}
{% block js %}
alert('注册页面')
{% endblock %}
7.6 登入界面
{% extends 'home.html' %}
{% block css %}
<style>
h1 {
color:chartreuse;
}
</style>
{% endblock %}
{% block content %}
<div>
<form action="" method="post">
<h1 class="text-center">登入页面</h1>
<p>用户名称:
<input type="text" name="username" class="form-control">
</p>
<p>用户密码:
<input type="password" name="password" class="form-control">
</p>
<input type="submit" value="登入" class="btn btn-block btn-info">
</form>
</div>
{% endblock %}
{% block js %}
alert('登入页面')
{% endblock %}
0. 在浏览器中 127.0.0.1:8000/home
1. 在浏览器中 127.0.0.1:8000/register
2. 在浏览器中 127.0.0.1:8000/login
8. 导入模板
将页面当作是一个模块,需要的时候直接导入。
0. 项目下 路由层 urls.py 添加代码
1. app01 应用下 视图层 views.py 添加代码
2. 项目下 templates 目录 models.html 写模板
3. 项目下 templates 目录 index.html 引用模板
url(r'^index', views.index)
def index(request):
return render(request, 'index.html')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
{% block css %}
{% endblock %}
</head>
<body>
<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>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试页面</title>
</head>
<body>
{% include 'models.html' %}
</body>
</html>
|