第1章 Django ORM相关操作
1.1 在一个py文件中使用django项目
1.2 返回QuerySet对象的方法有
1.2.1 特殊的QuerySet
1.3 返回具体对象的
1.4 返回布尔值的方法有:
1.5 返回数字的方法有
1.6 表单查询-双下划线
1.6.1 id__lt
1.6.2 id__in
1.6.3 name__contains
1.6.4 icontains
1.6.5 id__range
1.6.6 其它
第2章 ForeignKey操作(重点)
2.1 例:
2.1.1 设置model.py给多的添加外键
2.1.2 配置urls.py
2.1.3 编写views.py
2.1.4 service_list.html
2.1.5 server_add.html
第3章 下载文件从存储驱动
第4章 pycharm中的快捷键
4.1 部署配置static
第5章 路由系统进阶
5.1 基本格式
5.2 参数说明
5.3 url正则说明
5.3.1 注意事项
5.3.2 APPEND_SLASH=True
5.4 分组命名匹配
5.4.1 位置参数
5.4.2 关键字参数(命名分组)
5.4.3 视图分组(分页写法)
5.4.4 规范url路由分发
5.4.5 给视图参数传递额外的参数
5.5 url命名和反向解析(重)
5.5.1 静态传参
5.5.2 动态传参
5.6 命名空间
5.6.1 namespace
第6章 djaango--视图
6.1 视图函数FBV
6.2 视图类CBV
6.2.1 View模块
6.2.2 .as_view()方法
6.3 装饰器
6.3.1 FBV装饰器
6.3.2 CBV装饰器
6.3.3 介绍
6.3.4 method_decorator模块
6.3.5 扩展
6.3.6 CBV装饰器的三种方法
6.3.7 方法一:直接加载方法上面
6.3.8 方法二:加在dispatch方法上面
6.3.9 方法三:加在类上
6.4 request相关参数
6.4.1 path_info
6.4.2 method
6.4.3 GET
6.4.4 POST
6.4.5 body
6.5 属性
6.5.1 HttpRequest.scheme
6.5.2 HttpRequest.body
6.5.3 HttpRequest.path
6.5.4 HttpRequest.method
6.5.5 HttpRequest.encoding
6.5.6 HttpRequest.GET
6.5.7 6.HttpRequest.POST
6.5.8 HttpRequest.COOKIES
6.5.9 HttpRequest.FILES
6.5.10 HttpRequest.META
6.5.11 HttpRequest.user
6.5.12 HttpRequest.session
6.6 上传文件
6.7 response
6.7.1 介绍
6.7.2 使用方法
6.7.3 JsonResponse
6.7.4 render()
6.7.5 redirect()
6.7.6 设定json
第7章 模板引擎
7.1 常用语法
7.2 变量
7.2.1 例
7.3 Filters
7.3.1 default
7.3.2 filesizeformat
7.3.3 add
7.3.4 lower
7.3.5 title
7.3.6 length
7.3.7 slice
7.3.8 first
7.3.9 last
7.3.10 join
7.3.11 truncatechars
7.3.12 date
7.3.13 safe
7.3.14 自定义filter
7.3.15 for
7.3.16 with
7.3.17 注释
7.3.18 注意事项
7.4 模板继承
7.4.1 块(block)
7.4.2 组件
7.4.3 自定义simpletag
7.4.4 templatetags/my_inclusion.py
7.4.5 templates/result.html
7.4.6 templates/index.html
7.5 bootstrip没有数据优化
第1章 Django ORM相关操作
操作 |
查询结果 |
all(): |
查询所有结果 |
filter(**kwargs): |
它包含了与所给筛选条件相匹配的对象 |
get(**kwargs): |
返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 |
exclude(**kwargs): |
它包含了与所给筛选条件不匹配的对象 |
values(*field): |
返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列 |
values_list(*field): |
它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 |
order_by(*field): |
对查询结果排序 |
reverse(): |
对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。 |
distinct(): |
从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。) |
count(): |
返回数据库中匹配查询(QuerySet)的对象数量。 |
first(): |
返回第一条记录 |
last(): |
返回最后一条记录 |
exists(): |
如果QuerySet包含数据,就返回True,否则返回False |
1.1 在一个py文件中使用django项目
import os
if __name__=='__main__':
os.environ.setdefaul("DJANGO_SETTINGS_MODULE","mysite.setting")
import django
django.setup()
from app01 import models
ret = models.Person.objects.filer(age=18)
1.2 返回QuerySet对象的方法有
l all()
l filter()
l exclude()
l order_by()
l reverse()
l distinct()
1.2.1 特殊的QuerySet
l values() 返回一个可迭代的字典序列
l values_list() 返回一个可迭代的元祖序列
1.3 返回具体对象的
l get()
l first()
l last()
1.4 返回布尔值的方法有:
l exists()
1.5 返回数字的方法有
l count()
1.6 表单查询-双下划线
1.6.1 id__lt
获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1)
1.6.2 id__in
获取id等于11、22、33的数据
models.Tb1.objects.filter(id__in=[11, 22, 33])
not in
models.Tb1.objects.exclude(id__in=[11, 22, 33])
1.6.3 name__contains
获取name字段包含"ven"的
models.Tb1.objects.filter(name__contains="ven")
1.6.4 icontains
大小写不敏感
models.Tb1.objects.filter(name__icontains="ven")
1.6.5 id__range
id范围是1到3的,等价于SQL的bettwen and
models.Tb1.objects.filter(id__range=[1, 3])
1.6.6 其它
类似的还有:
startswith,istartswith, endswith, iendswith
date字段还可以:
models.Class.objects.filter(first_day__year=2017)
第2章 ForeignKey操作(重点)
class Publisher(models.Model):
name = models.CharField(max_length=12)
class Book(models.Model):
title = models.CharField(max_length=32)
publisher_id = models.ForeignKey(to="Publisher",on_delete=CASCADE)
注意:on_delete=CASCADE 在Django2.0中要添加,表示级联删除之意
解释:在出版社Publosher删除后BOOk也随之级联的操作,1.1默认是级联删除
django rest framwork
2.1 例:
设置primary外键
2.1.1 设置model.py给多的添加外键
方法一:
class Publisher(models.Model):
id = models.AutoField(primary_key=True)
name =models.CharField(max_length=32)
class Book(models.Model):
title = models.CharField(max_length=32)
publisher = models.ForeignKey(Publisher)
方法二:字符串表示调用的类(不用考虑顺序)
class Publisher(models.Model):
id = models.AutoField(primary_key=True)
name =models.CharField(max_length=32)
class Book(models.Model):
title = models.CharField(max_length=32)
publisher = models.ForeignKey('Publisher')#django自动加_id
2.1.2 配置urls.py
mtmy/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'app01',include('app01.urls'))
]
app01/urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'index/$', views.index,),
# service url
url(r'service_list/$', views.service_list, name='service_list'),
url(r'service_list/service_add/$', views.service_add,name='service_add'),
url(r'service_list/service_del/(?P<pk>d+)/$', views.service_del,name='service_del'),
#server url
url(r'server_list/$',views.server_list,name='server_list'),
url(r'server_list/server_add/$', views.AddServer.as_view(),name='server_add'),
url(r'service_list/server_del/(?P<pk>d+)/$', views.server_del,name='server_del'),
#manage url
url(r'manage_list/$',views.manage_list,name='manage_list'),
url(r'manage_list/manage_add/$', views.manage_add,name='manage_add'),
url(r'manage_list/manage_del/(?P<pk>d+)/$', views.manage_del,name='manage_del'),
]
2.1.3 编写views.py
from django.shortcuts import render,redirect,reverse,HttpResponse
from app01 import models
from django.views import View
# Create your views here.
def index(request):
return render(request, 'index.html')
def service_list(request):
services = models.ServiceList.objects.all()
#render 返回一个渲染的模板可以传入参数
return render(request,'service_list.html',{'services': services})
def service_add(request):
err_msg = ''
if request.method == 'POST':
service_name = request.POST.get('service_name')
if service_name:
service_list = models.ServiceList.objects.filter(service_name=service_name)
if service_list:
err_msg = '服务名称已经存在'
else:
service_obj = models.ServiceList.objects.create(service_name=service_name)
print(service_obj)
#redirect 接收一个url,表示跳转到指定的url
return redirect(reverse('service_list'))
else:
err_msg = '用户名不能为空'
return render(request,'service_add.html',{'error_msg':err_msg})
def service_del(request,pk):
serv_list = models.ServiceList.objects.filter(id=pk)
print(serv_list)
if serv_list:
serv_list[0].delete()
return redirect(reverse('service_list'))
else:
return HttpResponse('删除数据不存在')
def server_list(request):
server = models.HostsList.objects.all()
#render 返回一个渲染的模板可以传入参数
return render(request,'server_list.html',{ 'server':server })
def server_del(request,pk):
# service_id = request.GET.get(pk)
# print(pk)
serv_list = models.HostsList.objects.filter(id=pk)
print(serv_list)
if serv_list:
serv_list[0].delete()
return redirect(reverse('server_list'))
else:
return HttpResponse('删除数据不存在')
class AddServer(View):
def get(self,request):
services = models.ServiceList.objects.all()
manages = models.ManageList.objects.all()
return render(request,'server_add.html',{ 'service':services,'manage':manages})
def post(self,request):
new_name = self.request.POST.get('server_ip')
password = self.request.POST.get('password')
service_id = self.request.POST.get('service')
manage_id = self.request.POST.get('manage')
models.HostsList.objects.create(ipaddr=new_name,password=password,service=models.ServiceList.objects.get(id=service_id),manage=models.ManageList.objects.get(id=manage_id))
return redirect(reverse(server_list))
def manage_list(request):
#获取数据库所有数据
manage_list = models.ManageList.objects.all()
#render 返回一个渲染的模板可以传入参数server表示html中的for 中的server
return render(request,'manage_list.html',{ 'server':manage_list })
def manage_add(request):
err_msg = ''
if request.method == 'POST':
manage_id = request.POST.get('id')
manage_name = request.POST.get('name')
manage_pwd = request.POST.get('password')
if manage_id:
manage_list = models.ManageList.objects.filter(id=manage_id)
if manage_list:
err_msg = '服务器已经存在'
else:
manage_obj = models.ManageList.objects.create(id=manage_id,password=manage_pwd,name=manage_name)
# print(service_obj)
#redirect 接收一个url,表示跳转到指定的url
return redirect(reverse('manage_list'))
else:
err_msg = '用户名不能为空'
return render(request,'manage_add.html',{'error_msg':err_msg})
def manage_del(request,pk):
# service_id = request.GET.get(pk)
# print(pk)
serv_list = models.ManageList.objects.filter(id=pk)
print(serv_list)
if serv_list:
serv_list[0].delete()
return redirect(reverse('manage_list'))
else:
return HttpResponse('删除数据不存在')
2.1.4 service_list.html
{% extends 'base.html' %}
{% block content %}
<h2 class="sub-header">服务管理列表</h2>
<a class="btn btn-success" href="{% url 'service_add' %}">添加</a>
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>序号</th>
<th>ID</th>
<th>服务名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for service in services %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ service.id }}</td>
<td>{{ service.service_name }}</td>
<td>
<a class="btn btn-success btn-sm"
href="">编辑</a>
<a class="btn btn-danger btn-sm" href="{% url 'service_del' pk=service.id %}">删除</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" style="text-align: center">没有数据</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
2.1.5 server_add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
</head>
<body>
{% include 'nav.html' %}
<div class="container" style="margin-top: 70px">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<form class="form-horizontal" action="" method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">IPAddr</label>
<div class="col-sm-10">
<input type="text" name="server_ip" class="form-control" id="inputEmail3" placeholder="请添加服务IP">
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<input type="text" name="password" class="form-control" id="inputEmail3" placeholder="请添加服务器密码">
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Service_ID</label>
<div class="col-sm-10 ">
<select name="service" class="form-control" >
{% for service in service %}
<option value="{{ service.id }}">{{ service.service_name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Manage_ID</label>
<div class="col-sm-10 ">
<select name="manage" class="form-control" >
{% for manage in manage %}
<option value="{{ manage.id }}">{{ manage.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">提交</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
第3章 下载文件从存储驱动
第4章 pycharm中的快捷键
l Ctrl +d 复制
l CTrl + shilft + - 合起所有
l for +Tab html for 循环
l div. +table
4.1 部署配置static
https://docs.djangoproject.com/en/1.11/howto/static-files/deployment/
第5章 路由系统进阶
5.1 基本格式
Django1.15写法:
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
Django2.0写法
from django.urls import path
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
5.2 参数说明
l 正则表达式:一个正则表达式字符串
l views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
l 参数:可选的要传递给视图函数的默认参数(字典形式)
l 别名:一个可选的name参数
5.3 url正则说明
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
5.3.1 注意事项
l urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
l 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
l 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
l 每个正则表达式前面的'r' 是可选的但是建议加上
5.3.2 APPEND_SLASH=True
解释:
Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。
补充说明
是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True
例:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^blog/$', views.blog),
]
5.4 分组命名匹配
语法:
(?P<name>pattern)
name是组的名称
pattern是要匹配的模式。
例:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
#0到9数字中匹配4个数字
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。
例如,针对url /articles/2017/12/相当于按以下方式调用视图函数:
views.month_archive(request, year="2017", month="12")
5.4.1 位置参数
urls.py
url(r'edit_publisher/(d+)/$',views.edit_publisher),
html
<p>
id号:
<input type="text" name="nid" value="{{ pub_obj.nid }}" >
</p>
<p>
姓名:
<input type="text" name="publisher_name" value="{{ pub_obj.name}}">
</p>
views.py
def edit_publisher(request,nid):
# nid = request.POST.get('nid')
# 获取编辑的对象
if request.method == 'POST':
publisher_name = request.POST.get('publisher_name')
pub_obj = models.Publisher.objects.get(nid=nid)
pub_obj.name = publisher_name
# 向数据库提交
pub_obj.save()
return redirect('/publisher_list/')
# nid = request.GET.get('id')
pub_obj = models.Publisher.objects.get(nid=nid)
return render(request, 'edit_publisher.html', {'pub_obj': pub_obj})
页面访问:
5.4.2 关键字参数(命名分组)
urls.py
url(r'edit_publisher/(?P<pk>d+)/$',views.edit_publisher),
views.py
def edit_publisher(request,pk):
# nid = request.POST.get('nid')
# 获取编辑的对象
if request.method == 'POST':
publisher_name = request.POST.get('publisher_name')
pub_obj = models.Publisher.objects.get(nid=pk)
pub_obj.name = publisher_name
# 向数据库提交
pub_obj.save()
return redirect('/publisher_list/')
# nid = request.GET.get('id')
pub_obj = models.Publisher.objects.get(nid=pk)
return render(request, 'edit_publisher.html', {'pub_obj': pub_obj})
浏览器访问:
5.4.3 视图分组(分页写法)
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$,views.page),
url(r'^blog/page(?P<num>[0-9]+)/$',views.page)
]
views.py中可以为num指定默认值
#
def page(request,num="10"):
pass
5.4.4 规范url路由分发
解释:协同开发的作用,定义项目url保持编写规范
APP01项目目录中建立urls.py
#将原有项目的url移至app01.urls下
app01.urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
# 定义URL和函数的对应关系
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/home', views.home),
url(r'^index/$',views.index),
url(r'^login/$',views.login),
# url(r'^index/(?P<pk>d+)/$',views.publisher_list),
url(r'^publisher_list/$',views.publisher_list),
url(r'add_publisher',views.add_publisher),
url(r'del_publisher',views.del_publisher),
url(r'edit_publisher/(?P<pk>d+)/$',views.edit_publisher),
# url(r'edit_publisher',views.edit_publisher),
]
#主urls.py
from django.conf.urls import url,include
from django.contrib import admin
# 定义URL和函数的对应关系
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'app01', include('app01.urls')),
]
浏览器访问:
5.4.5 给视图参数传递额外的参数
URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url() 可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。
例如:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。
当传递额外参数的字典中的参数和URL中捕获值的命名关键字参数同名时,函数调用时将使用的是字典中的参数,而不是URL中捕获的参数。
5.5 url命名和反向解析(重)
解释:给url起了一个名字,用的时候可以直接解析到地址
5.5.1 静态传参
语法:
1)定义url : name= 'add'
urlpatterns = [
url(r'index/home',views.home),
url(r'index/$',views.index),
url(r'login/$',views.login),
url(r'publisher_list/$',views.publisher_list,name='publisher'),
url(r'publisher_list/add_publisher/$',views.add_publisher,name='add'),
url(r'publisher_list/del_publisher/$',views.del_publisher),
url(r'publisher_list/edit_publisher/$',views.edit_publisher),
]
2)更改模板变量 {% url 'add' %}
<thead>
<tr class="active text-center" id="tr">
<td>用户顺序</td>
<td>用户_ID</td>
<td>用户名</td>
<td>密码</td>
<td>操作管理</td>
</tr>
</thead>
<tbody class="text-center" >
#原始调用
#<a type="button" class="btn btn-success " href="/add_publisher/">增加新成员</a>
<a type="button" class="btn btn-success " href="{% url 'add' %}">增加新成员</a>
{% for i in pub %}
<tr >
<td class="info" >{{ forloop.counter }}</td>
<td class="success">{{ i.nid }}</td>
<td class="warning">{{ i.name}}</td>
<td class="warning">{{ i.password}}</td>
<td><a type="button" class="btn btn-danger bg-primary text-primary" href="/del_publisher/?id={{ i.nid }}"><button>删除</button></a>
<a type="button" class="btn btn-warning text-primary bg-primary " href=" /edit_publisher/?id={{ i.nid }}"><button>编辑</button></a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
3)修改views.py : reverse('别名')
from diango.import reverse
def add_publisher(request):
err_msg = ''
if request.method == 'POST':
publisher_name = request.POST.get('publisher_name')
publisher_password = md5(publisher_name,request.POST.get('publisher_password'))
if publisher_name:
pub_list = models.Publisher.objects.filter(name=publisher_name)
print(pub_list)
if pub_list:
err_msg = '用户名已存在'
else:
pub_obj = models.Publisher.objects.create(name=publisher_name,password=publisher_password)
print(pub_obj)
# return redirect('/publisher_list/')
return redirect(reverse('publisher'))
else:
err_msg = '用户名不能为空'
return render(request, 'add_publisher.html', {'err_msg': err_msg})
5.5.2 动态传参
解释:针对参数值为动态多个值时
1)urls.py (?P<pk>d+)/$ 动态传参
语法:
url(r'publisher_list/edit_publisher/(?P<pk>d+)/$',views.edit_publisher,name='edd'),
]
2)views.edit_publisher()
def edit_publisher(request,pk):
#位置传参
# nid = request.POST.get('nid')
# 获取编辑的对象
if request.method == 'POST':
publisher_name = request.POST.get('publisher_name')
pub_obj = models.Publisher.objects.get(nid=pk)
pub_obj.name = publisher_name
# 向数据库提交
pub_obj.save()
return redirect(reverse('publisher'))
# nid = request.GET.get('nid')
pub_obj = models.Publisher.objects.get(nid=pk)
return render(request, 'edit_publisher.html', {'pub_obj': pub_obj})
3)修改publisher_list.html
语法:
{% url 'edd' pk=i.nid %}"
<thead>
<tr class="active text-center" id="tr">
<td>用户顺序</td>
<td>用户_ID</td>
<td>用户名</td>
<td>密码</td>
<td>操作管理</td>
</tr>
</thead>
<tbody class="text-center" >
<a type="button" class="btn btn-success " href="{% url 'add' %}">增加新成员</a>
{% for i in pub %}
<tr >
<td class="info" >{{ forloop.counter }}</td>
<td class="success">{{ i.nid }}</td>
<td class="warning">{{ i.name}}</td>
<td class="warning">{{ i.password}}</td>
<td><a type="button" class="btn btn-danger bg-primary text-primary" href="/del_publisher/?id={{ i.nid }}"><button>删除</button></a>
<a type="button" class="btn btn-warning text-primary bg-primary " href="{% url 'edd' pk=i.nid %}"><button>编辑</button></a></td>
</tr>
{% endfor %}
页面访问:
5.6 命名空间
解释:不同业务定义url规范,避免不同项目之间调用冲突
5.6.1 namespace
project中的urls.py
from django.conf.urls import url, include
urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]
appo1中的urls.py
from django.conf.urls import url
from app01 import views
app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>d+)/$', views.detail, name='detail')
]
此时,当两个app中的 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的url.
语法:
'命名空间名称:URL名称'
模板中使用:
{% url 'app01:detail' pk=12 pp=99 %}
views中的函数中使用
v = reverse('app01:detail', kwargs={'pk':11})
这样即使app中URL的命名相同,我也可以反转得到正确的URL了。
第6章 djaango--视图
6.1 视图函数FBV
基于view函数的视图为FBV视图:
# FBV版添加班级
def add_class(request):
if request.method == "POST":
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
return render(request, "add_class.html")
6.2 视图类CBV
语法:
基于类的视图为CBV视图:
# CBV版添加班级
from django.views import View
class AddClass(View):
def get(self, request):
return render(request, "add_class.html")
def post(self, request):
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
注意:
使用CBV时,urls.py中也做对应的修改:
# urls.py中
url(r'^add_class/$', views.AddClass.as_view()),
6.2.1 View模块
写类之前pytho提供了一个类的模块View
6.2.2 .as_view()方法
解释:与FBV不同的是,CBV定义urls.py的方法如下:
# urls.py中
url(r'^add_class/$', views.AddClass.as_view()),
6.3 装饰器
6.3.1 FBV装饰器
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
ret = func(*args, **kwargs)
end_time = time.time()
print("used:", end_time-start_time)
return ret
return inner
# FBV版添加班级
@wrapper
def add_class(request):
if request.method == "POST":
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
return render(request, "add_class.html")
6.3.2 CBV装饰器
6.3.3 介绍
类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。
6.3.4 method_decorator模块
Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。
# CBV版添加班级
from django.views import View
from django.utils.decorators import method_decorator
class AddClass(View):
@method_decorator(wrapper)
def get(self, request):
return render(request, "add_class.html")
def post(self, request):
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
6.3.5 扩展
# 使用CBV时要注意,请求过来后会先执行dispatch()这个方法,如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,这个dispatch方法就和在FBV上加装饰器的效果一样。
class Login(View):
def dispatch(self, request, *args, **kwargs):
print('before')
obj = super(Login,self).dispatch(request, *args, **kwargs)
print('after')
return obj
def get(self,request):
return render(request,'login.html')
def post(self,request):
print(request.POST.get('user'))
return HttpResponse('Login.post')
6.3.6 CBV装饰器的三种方法
模块倒入method_decorator
from django.utils.decorators import method_decorator
def timer(func):
def inner(request, *args, **kwargs):
now = time.time()
ret = func(request, *args, **kwargs)
print("函数执行时间是{}".format(time.time() - now))
return ret
return inner
6.3.7 方法一:直接加载方法上面
class AddPublisher(View):
# http_method_names = ['get']
def dispatch(self, request, *args, **kwargs):
ret = super().dispatch(request, *args, **kwargs)
return ret
@method_decorator(timer)
def get(self, request):
return render(request, 'publisher_add.html')
def post(self, request):
print(request.body)
new_name = self.request.POST.get('name')
models.Publisher.objects.create(name=new_name)
return redirect(reverse('app01:publisher'))
6.3.8 方法二:加在dispatch方法上面
class AddPublisher(View):
# 只需要加一条就可以同时获取get和POST最方便
@method_decorator(timer)
def dispatch(self, request, *args, **kwargs):
ret = super().dispatch(request, *args, **kwargs)
return ret
def get(self, request):
return render(request, 'publisher_add.html')
def post(self, request):
print(request.body)
new_name = self.request.POST.get('name')
models.Publisher.objects.create(name=new_name)
return redirect(reverse('app01:publisher'))
6.3.9 方法三:加在类上
@method_decorator(timer,name='post')
@method_decorator(timer,name='get')
class AddPublisher(View):
# http_method_names = ['get']
@method_decorator(timer)
def dispatch(self, request, *args, **kwargs):
ret = super().dispatch(request, *args, **kwargs)
return ret
def get(self, request):
return render(request, 'publisher_add.html')
def post(self, request):
print(request.body)
new_name = self.request.POST.get('name')
models.Publisher.objects.create(name=new_name)
return redirect(reverse('app01:publisher'))
6.4 request相关参数
6.4.1 path_info
返回用户访问url,不包括域名
6.4.2 method
请求中使用的HTTP方法的字符串表示,全大写表示。
6.4.3 GET
包含所有HTTP GET参数的类字典对象
6.4.4 POST
包含所有HTTP POST参数的类字典对象
6.4.5 body
请求体,byte类型 request.POST的数据就是从body里面提取到的
6.5 属性
属性:
django将请求报文中的请求行、头部信息、内容主体封装成 HttpRequest 类中的属性。
除了特殊说明的之外,其他均为只读的。
6.5.1 HttpRequest.scheme
表示请求方案的字符串(通常为http或https)
6.5.2 HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
另外,我们还可以用 python 的类文件方法去操作它,详情参考 HttpRequest.read() 。
6.5.3 HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
6.5.4 HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
6.5.5 HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
6.5.6 HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
6.5.7 6.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
6.5.8 HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
6.5.9 HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
6.5.10 HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
6.5.11 HttpRequest.user
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
6.5.12 HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
6.6 上传文件
view.py
from django.shortcuts import render, redirect, reverse, HttpResponse
from app01 import models
from django.views import View
class Upload(View):
def get(self, request):
return render(request, 'upload.html')
def post(self, request):
my_file = request.FILES.get('my_file')
print(my_file.name)
with open(my_file.name, 'wb') as f:
for chunk in my_file.chunks():
f.write(chunk)
return HttpResponse('ok')
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="my_file">
<button type="submit">提交</button>
</form>
</body>
</html>
urls.py
url(r'^pub/add/$', views.AddPublisher.as_view(),name='publisher_add')
6.7 response
6.7.1 介绍
与由Django自动创建的HttpRequest对象相比,HttpResponse对象是我们的职责范围了。我们写的每个视图都需要实例化,填充和返回一个HttpResponse。
HttpResponse类位于django.http模块中。
6.7.2 使用方法
传递字符串
from django.http import HttpResponse
response = HttpResponse("Here's the text of the Web page.")
response = HttpResponse("Text only, please.", content_type="text/plain")
设置或删除响应头信息
response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']
属性
HttpResponse.content:响应内容
HttpResponse.charset:响应内容的编码
HttpResponse.status_code:响应的状态码
6.7.3 JsonResponse
JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。
from django.http import JsonResponse
response = JsonResponse({'foo': 'bar'})
print(response.content)
b'{"foo": "bar"}'
默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。
response = JsonResponse([1, 2, 3], safe=False)
6.7.4 render()
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
参数:
l request: 用于生成响应的请求对象。
l template_name:要使用的模板的完整名称,可选的参数
l context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
l content_type:生成的文档要使用的MIME类型。默认为 DEFAULT_CONTENT_TYPE 设置的值。默认为'text/html'
l status:响应的状态码。默认为200。
l useing: 用于加载模板的模板引擎的名称。
例:
from django.shortcuts import render
def my_view(request):
# 视图的代码写在这里
return render(request, 'myapp/index.html', {'foo': 'bar'})
等价于
from django.http import HttpResponse
from django.template import loader
def my_view(request):
# 视图代码写在这里
t = loader.get_template('myapp/index.html')
c = {'foo': 'bar'}
return HttpResponse(t.render(c, request))
6.7.5 redirect()
参数可以是:
l 一个模型:将调用模型的get_absolute_url() 函数
l 一个视图,可以带有参数:将使用urlresolvers.reverse 来反向解析名称
l 一个绝对的或相对的URL,将原封不动的作为重定向的位置。
l 默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。
传递一个具体的ORM对象(了解即可)
将调用具体ORM对象的get_absolute_url() 方法来获取重定向的URL:
from django.shortcuts import redirect
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect(object)
传递一个视图的名称
def my_view(request):
...
return redirect('some-view-name', foo='bar')
传递要重定向到的一个具体的网址
def my_view(request):
...
return redirect('/some/url/')
当然也可以是一个完整的网址
def my_view(request):
...
return redirect('http://example.com/')
默认情况下,redirect() 返回一个临时重定向。以上所有的形式都接收一个permanent 参数;如果设置为True,将返回一个永久的重定向:
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect(object, permanent=True)
前端交互
自带
区别
建议直接用json格式少一步反序列化
6.7.6 设定json
第7章 模板引擎
7.1 常用语法
Django模板中只需要记两种特殊符号:
{{ }}和 {% %}
{{ }}表示变量,在模板渲染的时候替换成值,{% %}表示逻辑相关的操作。
7.2 变量
{{ 变量名 }}
变量名由字母数字和下划线组成。
点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。
7.2.1 例
view中的代码
def template_test(request):
l = [11, 22, 33]
d = {"name": "alex"}
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def dream(self):
return "{} is dream...".format(self.name)
Alex = Person(name="Alex", age=34)
Egon = Person(name="Egon", age=9000)
Eva_J = Person(name="Eva_J", age=18)
person_list = [Alex, Egon, Eva_J]
return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})
模板中支持的写法:
{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}
注:当模板系统遇到一个(.)时,会按照如下的顺序去查询:
在字典中查询
属性或者方法
数字索引
7.3 Filters
翻译为过滤器,用来修改变量的显示结果。
语法: {{ value|filter_name:参数 }}
'|'左右没有空格没有空格没有空格
7.3.1 default
{{ value|default:"nothing"}}
如果value值没传的话就显示nothing
注:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用。
7.3.2 filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}
如果 value 是 123456789,输出将会是 117.7 MB。
7.3.3 add
给变量加参数
{{ value|add:"2" }}
value是数字4,则输出结果为6。
{{ first|add:second }}
如果first是 [1,.2,3] ,second是 [4,5,6] ,那输出结果是 [1,2,3,4,5,6] 。
7.3.4 lower
小写
{{ value|lower }}
upper
大写
{{ value|upper}}
7.3.5 title
标题
{{ value|title }}
ljust
左对齐
"{{ value|ljust:"10" }}"
rjust
右对齐
"{{ value|rjust:"10" }}"
center
居中
"{{ value|center:"15" }}"
7.3.6 length
{{ value|length }}
返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
7.3.7 slice
切片
{{value|slice:"2:-1"}}
7.3.8 first
取第一个元素
{{ value|first }}
7.3.9 last
取最后一个元素
{{ value|last }}
7.3.10 join
使用字符串拼接列表。同python的str.join(list)。
{{ value|join:" // " }}
7.3.11 truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:截断的字符数
{{ value|truncatechars:9}}
7.3.12 date
日期格式化
{{ value|date:"Y-m-d H:i:s"}}
可格式化输出的字符:点击查看。
7.3.13 safe
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
比如:
value = "<a href='#'>点我</a>"
{{ value|safe}}
时间格式全局化
7.3.14 自定义filter
自定义过滤器只是带有一个或两个参数的Python函数:
n 变量(输入)的值 - -不一定是一个字符串
n 参数的值 - 这可以有一个默认值,或完全省略
例如,在过滤器{{var | foo:“bar”}}中,过滤器foo将传递变量var和参数“bar”。
自定义filter代码文件摆放位置:
app01/
__init__.py
models.py
templatetags/ # 在app01下面新建一个package package
__init__.py
app01_filters.py # 建一个存放自定义filter的py文件
views.py
编写自定义filter
from django import template
register = template.Library()
@register.filter
def fill(value, arg):
return value.replace(" ", arg)
@register.filter(name="addSB")
def add_sb(value):
return "{} SB".format(value)
使用自定义filter
{# 先导入我们自定义filter那个文件 #}
{% load app01_filters %}
{# 使用我们自定义的filter #}
{{ somevariable|fill:"__" }}
{{ d.name|addSB }}
7.3.15 for
<ul>
{% for user in user_list %}
<li>{{ user.name }}</li>
{% endfor %}
</ul>
for循环可用的一些参数:
Variable Description
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
for ... empty
<ul>
{% for user in user_list %}
<li>{{ user.name }}</li>
{% empty %}
<li>空空如也</li>
{% endfor %}
</ul>
if,elif和else
{% if user_list %}
用户人数:{{ user_list|length }}
{% elif black_list %}
黑名单数:{{ black_list|length }}
{% else %}
没有用户
{% endif %}
当然也可以只有if和else
{% if user_list|length > 5 %}
七座豪华SUV
{% else %}
黄包车
{% endif %}
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
7.3.16 with
定义一个中间变量
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
csrf_token
这个标签用于跨站请求伪造保护。
在页面的form表单里面写上{% csrf_token %}
7.3.17 注释
{# ... #}
7.3.18 注意事项
1. Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %}
...
{% endif %}
2. Django的模板语言中属性的优先级大于方法
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中:
{{ data.items }}
默认会取d的items key的值。
7.4 模板继承
母板
<!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' %}
7.4.1 块(block)
通过在母板中使用{% block xxx %}来定义"块"。
在子页面中通过定义母板中的block名来对应替换母板中相应的内容。
{% block page-main %}
<p>世情薄</p>
<p>人情恶</p>
<p>雨送黄昏花易落</p>
{% endblock %}
7.4.2 组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
{% include 'navbar.html' %}
静态文件相关
{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件时使用:
{% load static %}
<script src="{% static "mytest.js" %}"></script>
某个文件多处被用到可以存为一个变量
{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>
使用get_static_prefix
{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
或者
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
7.4.3 自定义simpletag
和自定义filter类似,只不过接收更灵活的参数。
定义注册simple tag
@register.simple_tag(name="plus")
def plus(a, b, c):
return "{} + {} + {}".format(a, b, c)
使用自定义simple tag
{% load app01_demo %}
{# simple tag #}
{% plus "1" "2" "abc" %}
inclusion_tag
示例:
7.4.4 templatetags/my_inclusion.py
from django import template
register = template.Library()
@register.inclusion_tag('result.html')
def show_results(n):
n = 1 if n < 1 else int(n)
data = ["第{}项".format(i) for i in range(1, n+1)]
return {"data": data}
7.4.5 templates/result.html
<ul>
{% for choice in data %}
<li>{{ choice }}</li>
{% endfor %}
</ul>
7.4.6 templates/index.html
<!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>inclusion_tag test</title>
</head>
<body>
{% load my_inclusion %}
{% show_results 10 %}
</body>
</html>
7.5 bootstrip没有数据优化
{% empty %}
<h2 class="sub-header">用户管理列表</h2>
<a class="btn btn-success" href="{% url 'app01:manage_add' %}">添加</a>
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>number</th>
<th>ID</th>
<th>name</th>
<th>password</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for server in server %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ server.id }}</td>
<td>{{ server.name }}</td>
<td>{{ server.password}}</td>
<td>
<a class="btn btn-success btn-sm"
href="">编辑</a>
<a class="btn btn-danger btn-sm" href="{% url 'app01:manage_del' pk=server.id %}">删除</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" style="text-align: center">没有数据</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}