创建django 项目
django-admin startproject mysite
目录介绍
mysite
- mysite # 对整个程序进行配置
- init
- settings # 配置文件
- url # URL对应关系
- wsgi # 遵循WSIG规范,生产环境中一般不用django自带的wsgi,而是这个uwsgi + nginx
- manage.py # 管理Django程序:
- python manage.py
- python manage.py startapp xx
- python manage.py makemigrations
- python manage.py migrate
创建app
python manage.py startapp cmdb
cmdb:
migrations 数据修改表结构,django根据这个来判断表是否有改动,有改动就可以通过命令更新数据库中的表结构
admin Django为我们提供的后台管理
apps 配置当前app
models ORM,写指定的类 通过命令可以创建数据库结构
tests 单元测试
views 业务代码
创建完项目后的基本配置:
数据库

1 DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.mysql', 4 'NAME':'dbname', 5 'USER': 'root', 6 'PASSWORD': 'xxx', 7 'HOST': '', 8 'PORT': '', 9 } 10 }
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
# 如下设置放置的与project同名的配置的 __init__.py文件中
import
pymysql
pymysql.install_as_MySQLdb()

1 TEMPLATE_DIRS = ( 2 os.path.join(BASE_DIR,'templates'), 3 ) 4 #这里就是配置模板文件夹的可以将 'templates’改成自己的
静态文件

1 STATIC_URL = '/static/' 2 STATICFILES_DIRS = ( 3 os.path.join(BASE_DIR,'static'), 4 )
路由系统:
1 def func(request): 2 # request.method GET / POST 3 4 # http://127.0.0.1:8009/home?nid=123&name=alex 5 # request.GET.get('',None) # 获取请求发来的而数据 6 7 # request.POST.get('',None) 8 9 10 # return HttpResponse("字符串") 11 # return render(request, "HTML模板的路径",{"obj":obj 给前端模板传递参数这里也可以用locals()传递所有本地变量}) 12 # return redirect('/只能填URL /home) 这里就又转发给url,然后转给home视图
获取数据基本方法
request.POST
request.GET
request.FILES
获取checkbox和select多选参数 request.POST.getlist('city')#获取的name 上传文件 # 上传文件,form标签做特殊设置增加enctype="multipart/form-data obj = request.FILES.get('image') obj.name #输出文件名字,如果打印obj实际返回的也是文件名,因为在类中定义了__str__或__repr__ 来指定类返回的输出,str优先级高于repr
#obj的type ===》<class 'django.core.files.uploadedfile.InMemoryUploadedFile'> f = open(obj.name, mode='wb') for item in obj.chunks(): f.write(item) f.close()
模板渲染基本方式:
获取变量 <div>{{current_user}}</div> for循环 {% for k,v in user_list.items %} {{ k }}:{{ v }} {% endfor %} if判断,注意模板语言中的空格不能少 {% if row == "zhangs" %} <li>{{ row }}</li> {% else %} <li>else 不需要end</li> {% endif %} 获取字典或列表指定值 <a> {{ user_list.1 }}等同于list[1] </a>、 <a> {{ user_dict.k1 等同于dict['k1']}} </a> <a> {{ user_dict.k2 }} </a>
for循环序号
{% for k in user_list %}
{{ forloop.counter }}循环计数,默认从1开始forloop.counter0 从0开始
{{ forloop.revccounter }}倒排序54321 ,也有0属性
{{ forloop.first }} 循环的第一次,值为true
{{ forloop.last }} 循环的最后一次,值为true
{{ forloop.parentloop }} 父循环的次数,这个很少用
{% endfor %}
模板继承
母板:{% block title %}{% endblock %}
子板:{% extends "base.html" %} 一个子版只能集成一个母板
{% block title %}{% endblock %}
{% include xxx.html %} 可以多个xxx.html,文件中也可以包含{{ 模板变量 }}
帮助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}} 将参数转成日期输出
{{ bio|truncatewords:"30" }} 输出参数的前30个字节
{{ my_list|first|upper }} 输出开头大写,全部大写
{{ name|lower }} 输小写
自定义tag实现上面帮助方法:
模板中的方法对我们来说还是比较少的,可以在某些情况下无法满足
1在app中创建templatetags文件夹,必须是这个名字
2创建任意 .py 文件

1 #!/usr/bin/env python 2 #coding:utf-8 3 from django import template 4 from django.utils.safestring import mark_safe 5 6 #必须是register 7 register = template.Library() 8 9 @register.simple_tag 10 def my_simple_time(a,b): 11 return a+b 12 13 14 15 @register.simple_tag 16 def my_input(id,arg): 17 result = "<input type='text' id='%s' class='%s' />" %(id,arg,) 18 return mark_safe(result)
3在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
4使用tag

1 {% my_simple_time 1 2 %} 2 {% my_input 'id_username' 'hide'%}
filter,跟tags很像
#!/usr/bin/env python #coding:utf-8 from django import template from django.utils.safestring import mark_safe register = template.Library() #定义tag @register.simple_tag def add(p1,p2): return p1 + p2 #定义filter @register.filter() def add2(p1,p2): return p1 + p2
html页面
和上面定义的帮助方法一样,filter只能接受2个参数。如果想接受多个需要改源码{{ par|add2:"30,222,aa,sss" }}冒号后面的字符串分割。
{{ par|add2:"30" }}
filter有个一个作用就是可以用if 判断,tags是无法完成的
{% if par1|add2:"33" %} ................. {% endif %}
FBV & CBV
fba:function base view
cbv:class base view
2者区别就是一个用函数式一个用类
函数这里就不演示了,这里演示一下类
创建类的视图,view.py
1 #导入模块1.8以上会有很多模板可以看看django.views.generic下的__init__.py 2 #可以参考这个http://ccbv.co.uk/ 3 from django.views.generic import View 4 #这个类必须继承view 5 class Home(View): 6 #方法:['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']可以查看View方法 7 #类名小写,类中会处理格式转换成小写,如果发的是get请求就执行这个方法 8 def get(self,request): 9 return HttpResponse("ok:get") 10 #如果发 11 def post(self,request): 12 return HttpResponse("ok:post")
url

1 增加一个url条目 2 url(r'^home/$', views.Home.as_view()),
django如何做到?
1 代码是view下的一个方法dispatch
2 def dispatch(self, request, *args, **kwargs):
3 #先把请求的方法转换成小写然后去对比方法列表是否存在
4 if request.method.lower() in self.http_method_names:
5 #这里就是利用了反射,方法列表中有就进行反射
6 handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
7 else:
8 handler = self.http_method_not_allowed
9 return handler(request, *args, **kwargs)
那用上面的代码来做些事情,上的方法可以在post、get等之前执行

1 #-*- coding:utf-8 -*- 2 from django.shortcuts import render,HttpResponse 3 4 # Create your views here. 5 from django.views.generic import View 6 7 class Home(View): 8 def dispatch(self, request, *args, **kwargs): 9 #先执行一下父类方法 10 func=super(Home,self).dispatch(request, *args, **kwargs) 11 #将子串反给客户端,在这个中间就可以加上自己的一些处理了 12 #这里就可以完成装饰器的功能了 13 return func 14 def get(self,request): 15 return HttpResponse("ok:get") 16 #如果发 17 def post(self,request): 18 return HttpResponse("ok:post")
url匹配
这个是匹配的url url(r'^detail-(d+)-(d+).html/$', views.detail) #方法 def detail(request,sid,uid): return HttpResponse(sid+'/'+uid) 这个在访问上没有什么问题,但是如果底层方法把入口的sid和uid写反了的话结果就会不一样了。那如何避免?
url改成下面的即可,用正则分组来完成,这样一来不管底层入口函数如何变化都不会有影响了
url(r'^detail-(?P<sid>d+)-(?P<uid>d+).html/$', views.detail)
url路由名称
url(r'^index/$', views.index,name='index_page'), 现在把r'^index/$改成asdasdasd这个样子,前端就必须更改,比较麻烦。django已经把这个问题解决了就是加name参数 <form action="{% url 'index_page' %}" method="POST" enctype="multipart/form-data"> 表单中的url写成这样{% url 'index_page' %} 就OK了,不管urlsr'^index/$'如何改变都不会有影响了
加参数{% url 'index_page' 1 %}
获取当前url,当编辑一个页面后还想返回到编辑前的这个页面
request.path_info
命令空间
将不同的匹配指向相同的方法view
项目url
urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^app01/',include('myapp.urls')), 下面这二个就是命名空间了,相同的app,不同的匹配规则(a/b)对应不同的namespace url(r'^a/',include('myapp.urls',namespace='author-polls')), url(r'^b/',include('myapp.urls',namespace='publisher-polls')), ]
app url写法
这个必须要有 app_name='app01' urlpatterns = [ url(r'^test/$', views.test,name='test'),必须要有name因为要reverse ]
view写法
def test(request): from django.core.urlresolvers import reverse #这里将namespace 的author-polls转成test url v=reverse('author-polls:test') print(v) return HttpResponse("Ok")
reverse反转一个url
urls
url(r'^index/(d+)$', views.index,name='index_page'),
url(r'^home/$', views.Home.as_view()),
方法,这个cbv或fbv都可以这里只是一个例子
class Home(View): def get(self,request): #1.8之前这样导入from django.urls import reverse from django.core.urlresolvers import reverse
#第一个参数是name对应的名字 new_path=reverse('index_page',args=(70,)) print(new_path) return HttpResponse(request.path_info)
总结url大致就三种

1 对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL ***** 2 3 url(r'^asdfasdfasdf/', views.index, name='i1'), 4 url(r'^yug/(d+)/(d+)/', views.index, name='i2'), 5 url(r'^buy/(?P<pid>d+)/(?P<nid>d+)/', views.index, name='i3'), 6 7 8 9 def func(request, *args, **kwargs): 10 from django.urls import reverse 11 12 url1 = reverse('i1') # asdfasdfasdf/ 13 url2 = reverse('i2', args=(1,2,)) # yug/1/2/ 14 url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/ 15 16 17 xxx.html 18 19 {% url "i1" %} # asdfasdfasdf/ 20 {% url "i2" 1 2 %} # yug/1/2/ 21 {% url "i3" pid=1 nid=9 %} # buy/1/9/
路由分发,实现多级的urls转发
urlpatterns = [ url(r'^admin/', include(admin.site.urls)),
#以app01开头的都转发到app01.urls去 url(r'^app01/',include('app01.urls')), ]
orm基本操作
select * from tb where id > 1
# 对应关系
models.tb.objects.filter(id__gt=1) 大于__gt
models.tb.objects.filter(id=1) 等于 =
models.tb.objects.filter(id__lt=1) 小于__lt

#增 def create_info(request): #第一种创建数据库的方法 #自增长字段和自添加字段不需要写 #id、modify_time、create_time # obj=models.CreateInfo.objects.create( # user='wangj', # email='asda@qq.com', # pwd='123456', # host_name='hadoop', # system_type='生产系统', # images_type='centosy7', # apply_status='yes', # flavor_type='4c_2g', # ) #第二种创建用户信息 # obj2=models.CreateInfo(user='mky',email='asd@1123.com',pwd='12345',host_name='hadoop',system_type='生产系统',images_type='centosy7',apply_status='yes',flavor_type='4c_2g') # obj2.save() #第三种创建用户信息,有点是第一种的变种利用字典方式 create_dic={ 'user':'lisi', 'email':'asda@qq.com', 'pwd':'123456', 'host_name':'hadoop', 'system_type':'生产系统', 'images_type':'centosy7', 'apply_status':'yes', 'flavor_type':'4c_2g',} obj=models.CreateInfo.objects.create(**create_dic) return HttpResponse("OK") #查 def select_info(request): #查询CreateInfo所有信息 #obj=models.CreateInfo.objects.all() #queryset 是django自定义的一个类型。这个是个列表格式[obj1,obj2,obj3]里面存放对象 #[<CreateInfo: CreateInfo object>, <CreateInfo: CreateInfo object>, <CreateInfo: CreateInfo object>] # print(obj) # for i in obj: # print(i.user,i.email,i.flavor_type) #循环后的结果 # (u'wangj', u'asda@qq.com', u'4c_2g') # (u'mky', u'asd@1123.com', u'4c_2g') # (u'lisi', u'asda@qq.com', u'4c_2g') #查询某个字段,如果可以重名那么这里就是多条.不管返回几条都是queryset 类型 #obj=models.CreateInfo.objects.filter(user='mky') #obj=models.CreateInfo.objects.filter(user='mky',enail="asdas@qq.com") return HttpResponse(obj) #删除 def delete_info(request): #删除表中所有数据 #models.CreateInfo.objects.all().delete() #删除符合条件的数据 models.CreateInfo.objects.filter(id=1).delete() #更新 def update_info(request): #更新所有用户的pwd字段值为123456 #models.CreateInfo.objects.all().update(pwd='123456') #指定用户更新 models.CreateInfo.objects.filter(user='mky').update(pwd='123456')
********** 注意 ***********
Django默认使用MySQLdb模块链接MySQL,py3中的mysql模块还没有。
主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可:
import pymysql
pymysql.install_as_MySQLdb()
类型介绍

1 AutoField(Field) 2 - int自增列,必须填入参数 primary_key=True 3 4 BigAutoField(AutoField) 5 - bigint自增列,必须填入参数 primary_key=True 6 7 注:当model中如果没有自增列,则自动会创建一个列名为id的列 8 from django.db import models 9 10 class UserInfo(models.Model): 11 # 自动创建一个列名为id的且为自增的整数列 12 username = models.CharField(max_length=32) 13 14 class Group(models.Model): 15 # 自定义自增列 16 nid = models.AutoField(primary_key=True) 17 name = models.CharField(max_length=32) 18 19 SmallIntegerField(IntegerField): 20 - 小整数 -32768 ~ 32767 21 22 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) 23 - 正小整数 0 ~ 32767 24 IntegerField(Field) 25 - 整数列(有符号的) -2147483648 ~ 2147483647 26 27 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) 28 - 正整数 0 ~ 2147483647 29 30 BigIntegerField(IntegerField): 31 - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 32 33 自定义无符号整数字段 34 35 class UnsignedIntegerField(models.IntegerField): 36 def db_type(self, connection): 37 return 'integer UNSIGNED' 38 39 PS: 返回值为字段在数据库中的属性,Django字段默认的值为: 40 'AutoField': 'integer AUTO_INCREMENT', 41 'BigAutoField': 'bigint AUTO_INCREMENT', 42 'BinaryField': 'longblob', 43 'BooleanField': 'bool', 44 'CharField': 'varchar(%(max_length)s)', 45 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 46 'DateField': 'date', 47 'DateTimeField': 'datetime', 48 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 49 'DurationField': 'bigint', 50 'FileField': 'varchar(%(max_length)s)', 51 'FilePathField': 'varchar(%(max_length)s)', 52 'FloatField': 'double precision', 53 'IntegerField': 'integer', 54 'BigIntegerField': 'bigint', 55 'IPAddressField': 'char(15)', 56 'GenericIPAddressField': 'char(39)', 57 'NullBooleanField': 'bool', 58 'OneToOneField': 'integer', 59 'PositiveIntegerField': 'integer UNSIGNED', 60 'PositiveSmallIntegerField': 'smallint UNSIGNED', 61 'SlugField': 'varchar(%(max_length)s)', 62 'SmallIntegerField': 'smallint', 63 'TextField': 'longtext', 64 'TimeField': 'time', 65 'UUIDField': 'char(32)', 66 67 BooleanField(Field) 68 - 布尔值类型 69 70 NullBooleanField(Field): 71 - 可以为空的布尔值 72 73 CharField(Field) 74 - 字符类型 75 - 必须提供max_length参数, max_length表示字符长度 76 77 TextField(Field) 78 - 文本类型 79 80 EmailField(CharField): 81 - 字符串类型,Django Admin以及ModelForm中提供验证机制 82 83 IPAddressField(Field) 84 - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制 85 86 GenericIPAddressField(Field) 87 - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 88 - 参数: 89 protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" 90 unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both" 91 92 URLField(CharField) 93 - 字符串类型,Django Admin以及ModelForm中提供验证 URL 94 95 SlugField(CharField) 96 - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) 97 98 CommaSeparatedIntegerField(CharField) 99 - 字符串类型,格式必须为逗号分割的数字 100 101 UUIDField(Field) 102 - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 103 104 FilePathField(Field) 105 - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能 106 - 参数: 107 path, 文件夹路径 108 match=None, 正则匹配 109 recursive=False, 递归下面的文件夹 110 allow_files=True, 允许文件 111 allow_folders=False, 允许文件夹 112 113 FileField(Field) 114 - 字符串,路径保存在数据库,文件上传到指定目录 115 - 参数: 116 upload_to = "" 上传文件的保存路径 117 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage 118 119 ImageField(FileField) 120 - 字符串,路径保存在数据库,文件上传到指定目录 121 - 参数: 122 upload_to = "" 上传文件的保存路径 123 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage 124 width_field=None, 上传图片的高度保存的数据库字段名(字符串) 125 height_field=None 上传图片的宽度保存的数据库字段名(字符串) 126 127 DateTimeField(DateField) 128 - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] 129 130 DateField(DateTimeCheckMixin, Field) 131 - 日期格式 YYYY-MM-DD 132 133 TimeField(DateTimeCheckMixin, Field) 134 - 时间格式 HH:MM[:ss[.uuuuuu]] 135 136 DurationField(Field) 137 - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 138 139 FloatField(Field) 140 - 浮点型 141 142 DecimalField(Field) 143 - 10进制小数 144 - 参数: 145 max_digits,小数总长度 146 decimal_places,小数位长度 147 148 BinaryField(Field) 149 - 二进制类型 150 151 字段
字段参数询

1 null 数据库中字段是否可以为空 2 db_column 数据库中字段的列名 3 db_tablespace 4 default 数据库中字段的默认值 5 primary_key 数据库中字段是否为主键 6 db_index 数据库中字段是否可以建立索引 7 unique 数据库中字段是否可以建立唯一索引 8 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 9 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 10 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引 11 12 verbose_name Admin中显示的字段名称 13 blank Admin中是否允许用户输入为空 14 editable Admin中是否可以编辑 15 help_text Admin中该字段的提示信息 16 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 17 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) 18 19 error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息; 20 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 21 如:{'null': "不能为空.", 'invalid': '格式错误'} 22 23 validators 自定义错误验证(列表类型),从而定制想要的验证规则 24 from django.core.validators import RegexValidator 25 from django.core.validators import EmailValidator,URLValidator,DecimalValidator, 26 MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 27 如: 28 test = models.CharField( 29 max_length=32, 30 error_messages={ 31 'c1': '优先错信息1', 32 'c2': '优先错信息2', 33 'c3': '优先错信息3', 34 }, 35 validators=[ 36 RegexValidator(regex='root_d+', message='错误了', code='c1'), 37 RegexValidator(regex='root_112233d+', message='又错误了', code='c2'), 38 EmailValidator(message='又错误了', code='c3'), ] 39 ) 40 41 参数
外键ForeignKey一对多
# Create your models here. class UserGroup(models.Model): #自增列必须加主键 uid = models.AutoField(primary_key=True) caption = models.CharField(max_length=32) class UserInfo(models.Model): username=models.CharField(max_length=16,verbose_name='用户名',help_text='django中的提示信息') password=models.CharField(max_length=60) email= models.EmailField(max_length=16) #运行中放在内存中,并没有放在表中,这个在django admin中提示下拉框选项,避免链表查询 user_type_id=( (1,'管理员'), (2,'普通用户'), ) user_type=models.IntegerField(choices=user_type_id,default=1) #to_field指定外键关联的字段,必须唯一。也可以不指定默认选择主键 user_group=models.ForeignKey('UserGroup',to_field='uid')
总结:

1 一对多: 2 3 a. 外键 4 b. 外键字段_id 5 #增加外键的值,这样直接增加比较方便 6 c. models.tb.object.create(name='root', user_group_id=1) 7 8 d. userlist = models.tb.object.all() 9 for row in userlist: 10 row.id 11 循环外键表的属性 12 row.user_group_id 13 row.user_group.caption
查询总结,objects.all()、values、values_list

1 def business(request): 2 #获取所有对象,objv1 是queryset 类型返回对象[obj,ob,obj] 3 objv1=models.Business.objects.all() 4 5 #values等同于 select id,caption from business. objv2 是queryset 类型返回字典['k1':'k2','k3':'k4'] 6 objv2=models.Business.objects.all().values("id","caption") 7 8 #objv2 是queryset 类型返回元组[(1,"市场"),(2,"业务")] 9 objv3=models.Business.objects.all().values_list("id","caption")

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <h1>业务线列表(objv1对象)</h1> 9 <ul> 10 {% for i in objv1 %} 11 <li>{{ i.id }}-{{ i.caption }}-{{ i.code }}</li> 12 {% endfor %} 13 </ul> 14 <h1>业务线列表(objv2字典)</h1> 15 <ul> 16 {% for i in objv2 %} 17 <li>{{ i.id }}-{{ i.caption }}</li> 18 {% endfor %} 19 </ul> 20 <h1>业务线列表(objv3元组)</h1> 21 <ul> 22 {% for i in objv3 %} 23 <li>{{ i.0 }}-{{ i.1 }}</li> 24 {% endfor %} 25 </ul> 26 </body> 27 </html>
跨表操作
def host(request): v1=models.Host.objects.all() for i in v1: #跨表获取数据i.b_id,i.b.caption,i.b.code,跨表查询以"点"获取 print(i.nid,i.hostname,i.ip,i.port,i.b_id,i.b.caption,i.b.code) #跨表打印数据 print(v1[1].b.caption) #values跨表查询,必须用双下划线"__"来代替上面的"点"。里面是[{k:v}] v2=models.Host.objects.all().values('nid','b__caption','b__code') for i in v2:
#这里可以看出上面values中的字段都是下面的key,在前端也是如此
#前端i['nid'],i['b__caption'],i['b__code']
print(i['nid'],i['b__caption'],i['b__code'])
#values_list返回的元组
v3=models.Host.objects.all().values_list('nid','b__caption','b__code')
for i in v2:
#因为返回的元组,所以这里必须用索引来取值,前端也是。
#前端例子 {{i.1}}
print(i[0],i[1],i[2])
return HttpResponse("OK")