1.内容回顾
1)Django请求生命周期
HTTP请求->WSGI服务器(WEB服务网关接口)->中间件->url(路由系统)->view(匹配视图函数)->views从model取数据->从前端拿模板->模板渲染给用户返回一个大的字符串(网页内容)
2)Session是什么?
Session:是保存在服务端的数据,当用户登录时,服务端生成随机字符串给客户端的浏览器,浏览器写到cookie里,服务器端把随机字符串保存起来,服务端的随机字符串和客户端的cookie里的随机字符串一一对应。
3)XSS是什么?
XSS:跨站脚本攻击 举例:评论(while循环,alert), 防止XSS(1.客户端提交什么数据,以安全的形式查看,当作字符串让用户访问,2.用户提交时过滤关键字,如script)
4)CSRF-POST(银行的例子) 两个网站
CSRF:跨站请求伪造(POST请求)
不仅发送数据,还要发送随机字符串(上一次POST请求获取到的)
2.今日内容:
Form组件
django框架提供了一个Form类,来处理web开发中的表单相关事项。众所周知,Form最常做的是对用户输入的内容进行验证,为此django的forms类提供了全面的内容验证和保留用户上次输入数据的支持。
Form作用有两个1.用户提交数据进行校验;2.保留上次输入内容
提交数据方式:1.Form提交;2.Ajax提交
1. 用户提交数据进行校验
- Form提交(刷新,失去上次内容) a. LoginForm(Form) 字段名 = xxxx.xxField() # 本质就是验证规则,正则表达式 字段名 = xxxx.xxField() # 本质验证规则,正则表达式 字段名 = xxxx.xxField() # 本质验证规则,正则表达式 字段名 = xxxx.xxField() # 本质验证规则,正则表达式 b. obj = LoginForm(用户提交的数据,request.POST) c. result = obj.is_valid() 进行校验 print(result)返回True 或者False d. obj.cleaned_data:是一个字典,如果校验成功了,拿到正确的值 e. obj.errors:是一个对象,包含所有的错误信息
内部原理
def login(request): if request.method == 'GET': return render(request, 'login.html') else: obj = LoginForm(request.POST) #is_valid """ 获取当前类所有的对象 1.LoginForm实例化时,self.fields中 self.fields={ 'user':正则表达式, 'pwd':正则表达式, } 2.循环self.fields, flag = True验证通过(用户名密码。。都输入正确) errors cleaned_data for k,v in self.fields.items(): k是user,pwd v是:正则表达式 input_value = request.POST.get(k):前端输入的值,写几个字段,就取谁 正则表达式和input_value进行正则匹配(这里用的是match) flag = False return flag """ if obj.is_valid():#如果正确 print(obj.cleaned_data)#字典类型 return redirect('http://www.baidu.com') else: print(obj.errors) return render(request, 'login.html', {'obj':obj})
def login(request): if request.method == 'GET': return render(request,'login.html') else: obj = LoginForm(request.POST) # is_valid """ 1. LoginForm实例化时, self.fields={ 'user': 正则表达式 'pwd': 正则表达式 } 2. 循环self.fields flag = True errors cleaned_data for k,v in self.fields.items(): # 1. user,正则表达式 input_value = request.POST.get(k) 正则表达式和input_value flag = False return flag """ if obj.is_valid(): print(obj.cleaned_data) else: print(obj.errors) return render(request,'login.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>用户登录</h1> <form id="f1" action="/login/" method="POST"> {% csrf_token %} <p> 用户名:<input type="text" name="user" />{{ obj.errors.user.0 }} </p> <p> 密码:<input type="password" name="pwd" />{{ obj.errors.pwd.0 }} </p> <input type="submit" value="提交"> <a onclick="submitForm();">提交</a> #onclick绑定事件 </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ $('.c1').remove(); #把以前的错误信息都清除掉 $.ajax({ url:'/ajax_login/', type:'POST', #提交方式 data:$('#f1').serialize(), #找到f1标签,jQuery ajax - serialize() 方法,serialize() 方法通过序列化表单值,创建 URL 编码文本字符串。 datatype:"JSON", #serialize()拼接字符串, user=alex&pwd=456&csrf_token=bing success:function(arg){ console.log(arg); if (arg.status){ }else{ $.each(arg.msg,function (index,value) { 循环把所有错误信息输出index,value(也就是key和value ) console.log(index,value); var tag = document.createElement('span'); #创建节点: tag.innerHTML = value[0]; #获取第一个错误信息,innerHTML 给节点添加html代码: tag.className = 'c1'; $('#f1').find('input[name="'+ index +'"]').after(tag); #在span标签的后面 //' input[name=" ' + index + ' "] '==input[name=user] }) } } }) } </script> </body> </html>
前端涉及知识点:
1) createElement(标签名) :创建一个指定名称的元素。
例:var tag=document.createElement(“input")
tag.setAttribute('type','text');
2)data:$('#f1').serialize() serialize() 方法可以操作已选取个别表单元素的 jQuery 对象,比如 <input>, <textarea> 以及 <select>。
不过,选择 <form> 标签本身进行序列化一般更容易些:
打包user,pwd,csrf_token,拼接字符串
咱们写的字典也会变成字符串
请求体:'user=alex&pwd=456&csrf_token=bing'
注意:render的本质还是返回HttpResponse(字符串)
return render():
def render(request, template_name, context=None, content_type=None, status=None, using=None):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
1.obj=Form()form组件类实例化时找到类中所有的字段 把这些字段 变成组合成字典; self.fields={‘user’:正则表达式1,‘pwd’:正则表达式2} 2.循环self.fields字典(自己写的字段) for k,v in self.fields.items(): K是user,pwd v是正则表达式 3.每次循环通过self.fields字典的键, 去get前端POST提交的数据 得到用户输入数据; input_value= request.post.get(‘k’)(所以form字段的名称,要和前端的name属性匹配) 4.拿到用户输入的数据 (input_value)和进行正则表达式匹配; 5.匹配成功flag=True 匹配失败flag=falsh,最后 return flag obj.is_valid=flag。
from django.shortcuts import render,HttpResponse,redirect from django.forms import Form from django.forms import fields class Login(Form): #from验证规则 用户名 6-10字符 required不能为空 name=fields.CharField(max_length=10, min_length=6, required=True, error_messages={ 'required':'用户名不能为空', #error_messages参数 自定义错误信息 'min_length':'太短了', 'max_length': "太长了", } ) # z注意name 必须和 from表单提交的一致,要么二则怎么对比校验呢 pwd= fields.CharField(min_length=3, required=True, error_messages={ 'required': '密码不能为空', # error_messages参数 自定义错误信息 'min_length': '太短了', 'max_length': "太长了", } ) def index(request): if request.method=='GET': return render(request,'login.html') else: obj=Login(request.POST) #把客户端提交来的form表单和 和匹配规则放在一起 res=obj.is_valid() #自动校验 给出结果 True 或者 False if res: #验证成功后obj.cleaned_data获取成功的数据,字典类型正好对应数据 的批量操作 print(obj.cleaned_data) return redirect('http://www.baidu.com') #obj.errors获取错误信息(对象类型)就可以传到前端显示了! else: return render(request,'login.html',{'obj':obj})
2.- Ajax提交(不刷新,上次内容自动保留)
PS: Ajax提交(页面不刷新,数据不清空) > Form提交(Form表单一刷新,页面刷新,输入的数据都会清空) 总结:
class Foo(Form): 字段 = 正则表达式 :是否可以为空,最长,最短 字段 = 自定义正则表达式 1. 常用 charField
... 定义正则表达式 参数: 验证:(本质上都是正则表达式) required error_messages 生成HTML标签: widget=widgets.Select, ******** 用于指定生成怎样的HTML,select,text,input/. label='用户名', # obj.t1.label disabled=False, # 是否可以编辑 label_suffix='--->', # Label内容后缀 initial='666', # 无用,猜测有问题应该在input框中显示默认值 help_text='。。。。。。', # 提供帮助信息
- 生成HTML标签
- 保留上次输入内容
IntegerField继承Field
CharField 继承Field
EmailField继承 CharField
URLField继承CharField
t4 = fields.URLField()
t5 = fields.SlugField() #字母数字下划线,内部也是正则表达式
t6 = fields.GenericIPAddressField()
t7 = fields.DateTimeField()
t8 = fields.DateField()
def ajax_login(request): # request.POST.get() import json ret = {'status':True,'msg':None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data)#{'user': 'alex', 'pwd': 'alexalexalexalexalex'} else: print(obj.errors)#obj.errors,是一个 对象(无序列表) ret['status'] = True ret['msg'] = obj.errors # error = json.dumps(obj.errors) # print(error) v = json.dumps(ret) print(v)#输入错误:输出{"status": true, "msg": {"user": ["This field is required."], "pwd": ["This field is required."]}} #输入正确:{"status": true, "msg": null} return HttpResponse(v)#提交错误时,<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li><li>pwd<ul class="errorlist"><li>This field is required.</li></ul></li></ul> #ajax提交 # {'user': 'alex', 'pwd': 'alexalexalexalexalex'} # return render()
<script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ $('.c1').remove(); $.ajax({ url:'/ajax_login/', type:'POST', data:$('#f1').serialize(), datatype:"JSON", success:function(arg){ console.log(arg); if (arg.status){ }else{ $.each(arg.msg,function (index,value) { console.log(index,value); var tag = document.createElement('span'); tag.innerHTML = value[0]; tag.className = 'c1'; $('#f1').find('input[name="'+ index +'"]').after(tag); }) } } }) } </script>
Ajax提交验证(不会刷新,上次输入内容自动保留)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ajx提交</title> </head> <body> <form method="post" action="/aja_login/" id="f1"> {%csrf_token%} <p>用户:<input type="text" name="name"></p> <p>密码:<input type="password" name="pwd"></p> <p><input type="button" onclick="Ajxform()" value="aja提交"></p> </form> </body> <script src="/static/zhanggen.js"></script> <script> function Ajxform(){ $('.c1').remove() $.ajax({ url:'/alogin/', type:'POST', dataType:'JSON', data:$('#f1').serialize(), success:function (args) { if (args.status){ } else{ {# {status: false, msg: Object}#} {# console.log(args);#} {# Jquery循环服务端 传过来的 错误信息对象#} $.each(args.msg,function (index,value) { console.log(index,value); {# index----> name ["太短了"]#} {# value-----pwd["密码不能为空"]#} var tag=document.createElement('span'); tag.innerHTML= value[0]; tag.className='c1'; console.log(index); {# 寻找input下 属性为 name 和pwd的标签(字符串拼接) 在他们后半加 上tag标签也就是错误 信息 #} $('#f1').find('input[name="'+ index +'"]').after(tag) }) } }})} </script> </html>
Views
from django.shortcuts import render,HttpResponse,redirect from django.forms import Form from django.forms import fields import json class Login(Form): #from验证规则 用户名 6-10字符 required不能为空 name=fields.CharField(max_length=10, min_length=6, required=True, error_messages={ 'required':'用户名不能为空', #error_messages参数 自定义错误信息 'min_length':'太短了', 'max_length': "太长了", } ) # z注意name 必须和 from表单提交的一致,否则二者怎么对比校验呢 pwd= fields.CharField(min_length=3, required=True, error_messages={ 'required': '密码不能为空', # error_messages参数 自定义错误信息 'min_length': '太短了', 'max_length': "太长了",}) def agx_login(request): ret={'status':True,'msg':None} if request.method=='GET': return render(request,'ajalogin.html') else: obj=Login(request.POST) ret['status']=False ret['msg']=obj.errors return HttpResponse(json.dumps(ret))
Form组件之常用字段和参数
Field required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀
动态生成HTML标签,保留用户上次输入的内容。
如何保留用户上次输入的内容?
由于form表单submit之后(发送post请求) 数据提交到 后端,不管前端输入的数据是否正确,服务端也要响应,所以页面会刷新;
所以无法保留用户上次输入的内容;如何解决呢?
1、把定义的定义的Form类,实例化(obj=Login() )内部调用一个__str__的方法,如果没有传值 返回<input type="text" name=“字段”>name='字段名空的input标签
2、把这个实例化之后的对象传到前端显示,让用户输入值;用户输入值通过post方法提交到后台。
3、如果后台实例化一个对象 obj=Login(request.POST)传入了值, <input type="text" name=“字段” value='request.post的数据'>然后后端再返回客户端就可以看到用户输入的值了!
from django.shortcuts import render,HttpResponse,redirect from django.forms import Form from django.forms import fields import json class Login(Form): #Form验证规则 用户名 6-10字符 required不能为空 name=fields.CharField(max_length=10, min_length=6, required=True, error_messages={ 'required':'用户名不能为空', #error_messages参数 自定义错误信息 'min_length':'太短了', 'max_length': "太长了", } ) # z注意name 必须和 from表单提交的一致,要么二则怎么对比校验呢 pwd= fields.CharField(min_length=3, required=True, error_messages={ 'required': '密码不能为空', # error_messages参数 自定义错误信息 'min_length': '太短了', 'max_length': "太长了",}) def index(request): ret={'status':True,'msg':None} if request.method=='GET': obj=Login() #自动生成空白的input标签 发送给客户端) return render(request,'login.html',{'obj':obj}) else: obj=Login(request.POST) #把客户端提交来的form表单和 和匹配规则放在一 res=obj.is_valid() #自动生成空白的input标签 发送 if res: #验证成功后obj.cleaned_data获取成功的数据,字典类型正好对应数据 的批量操作 return HttpResponse('OK') #obj.errors获取错误信息(对象类型)就可以传到前端显示了! else: return render(request,'login.html',{'obj':obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post" action="/login/" id="f1" novalidate > {%csrf_token%} <h1>用户登录</h1> <p>用户名 {{obj.name}}{{ obj.name.errors.0}}</p> <p>密码:{{ obj.pwd}}{{ obj.pwd.errors.0}}</p> <p><input type="submit" value="登录"></p> </form> </body> </html>
方式一(推荐):
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class MyForm(Form): user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.Select ) def __init__(self, *args, **kwargs): super(MyForm,self).__init__(*args, **kwargs) # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
老师管理:
老师列表:
class TeacherForm(Form): tname = fields.CharField(min_length=2) xx = fields.MultipleChoiceField( #或者ChoiceField choices=models.Classes.objects.values_list('id','title'), widget=widgets.SelectMultiple ) def __init__(self,*args,**kwargs): super(TeacherForm,self).__init__(*args,**kwargs) self.fields['xx'].widget.choices = models.Classes.objects.values_list('id','title') 每实例化一次取一次值(也就是每进行一次操作从数据库取一次数据) obj = TeacherForm() 实例化成对象 1.找到所有字段 2.self.fields={ tname:fields.CharField(min_length=2) }
def teacher_list(request): tea_list = models.Teacher.objects.all() print(tea_list)#<QuerySet [<Teacher: Teacher object>, <Teacher: Teacher object>, <Teacher: Teacher object>, <Teacher: Teacher object>]> # print(tea_list.tname, tea_list.age, tea_list.title) return render(request,'teacher_list.html',{'tea_list':tea_list})
class TeacherForm(Form): tname = fields.CharField(min_length=2) xx = fields.MultipleChoiceField( #或者ChoiceField:单选 choices=models.Classes.objects.values_list('id','title'), widget=widgets.SelectMultiple ) def __init__(self,*args,**kwargs): super(TeacherForm,self).__init__(*args,**kwargs) self.fields['xx'].widget.choices = models.Classes.objects.values_list('id','title') # obj = TeacherForm() #1.找到所有字段 #2.self.fields={ # tname:fields.CharField(min_length=2) # }
def add_teacher(request): if request.method == "GET": obj = TeacherForm() return render(request,'add_teacher.html',{'obj':obj}) else: obj = TeacherForm(request.POST) if obj.is_valid(): # print(obj.cleaned_data)#{'tname': '方少伟', 'xx': ['2', '3']} xx = obj.cleaned_data.pop('xx')#把不必要的东西删掉 row = models.Teacher.objects.create(**obj.cleaned_data) print(row)# row.c2t.add(*xx)#添加一个字典到第三张表 return redirect('/teacher_list/') # print('okokokokok') return render(request,'add_teacher.html',{'obj':obj})
修复Bug,刷新无法动态显示数据库内容: 方式一: class TeacherForm(Form): tname = fields.CharField(min_length=2) # xx = form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all()) # xx = form_model.ModelChoiceField(queryset=models.Classes.objects.all()) 方式二: class TeacherForm(Form): tname = fields.CharField(min_length=2) xx = fields.MultipleChoiceField( widget=widgets.SelectMultiple ) def __init__(self,*args,**kwargs): super(TeacherForm,self).__init__(*args,**kwargs) self.fields['xx'].widget.choices = models.Classes.objects.values_list('id','title')
Select框: 单选的方案有两种 cls_id = fields.IntegerField( # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')]) widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'}) ) cls_id = fields.ChoiceField( choices=models.Classes.objects.values_list('id','title'), widget=widgets.Select(attrs={'class': 'form-control'}) ) obj = FooForm({'cls_id':1}) 多选的方案只有一种 xx = fields.MultipleChoiceField( choices=models.Classes.objects.values_list('id','title'), widget=widgets.SelectMultiple )
方式二:适用于写比较简单的程序,不推荐用这个,必须跟model结合起来用,耦合性太强,依赖数据,依赖__str__方法,程序越写越大,数据库可能会单独拆分出去,有人专门写数据库操作,客户端发HTTP请求,服务端会把结果返回给你,客户端拿到的是JSON对象,那就不是一个models对象了。
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
from django.forms import models as form_model class TeacherForm(Form): tname = fields.CharField(min_length=2) xx=form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all())
添加老师会出现如下现象:select框全是Classes对象
解决方式:
class Classes(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title class Student(models.Model): name = models.CharField(max_length=32) email = models.CharField(max_length=32) age = models.IntegerField() cls = models.ForeignKey('Classes') class Teacher(models.Model): tname = models.CharField(max_length=32) c2t = models.ManyToManyField('Classes')
在班级类添加一个__str__方法:
def __str__(self): return self.title
然后select框恢复正常:
Form组件:生成常用标签
class TestForm(Form): t1 = fields.CharField( widget=widgets.Textarea(attrs={}) ) t2 = fields.CharField( widget=widgets.CheckboxInput # ) t3 = fields.MultipleChoiceField( choices = [(1,'篮球'),(2,'足球'),[3,'排球']], widget=widgets.CheckboxSelectMultiple #多选 )
t4 = fields.MultipleChoiceField( #这里也可以写成ChoiceField
choices = [(1,'游泳'),(2,'写代码'),[3,'旅游']],
widget=widgets.RadioSelect #单选
)
t5 = fields.FileField(
idget=widgets.FileInput
)
def test(request): obj = TestForm() return render(request,'test.html',{'obj':obj})
is_valid-->self.errors错误信息(def errors(self))-->self.full_clean()做验证-->def full_clean(self)-->self._clean_fields(self): def is_valid(self): """ Returns True if the form has no errors. Otherwise, False. If errors are being ignored, returns False. """ return self.is_bound and not self.errors 初始化时,data(True,要进行验证) initial(False) 等于True或者False @property def errors(self): "Returns an ErrorDict for the data provided for the form" if self._errors is None: self.full_clean() 做验证 return self._errors def full_clean(self): """ Cleans all of self.data and populates self._errors and self.cleaned_data. """ self._errors = ErrorDict() if not self.is_bound: # Stop further processing. return self.cleaned_data = {}空字典 字典格式,做校验时填充数据 # If the form is permitted to be empty, and none of the form data has # changed from the initial data, short circuit any validation. if self.empty_permitted and not self.has_changed(): return self._clean_fields() 字段 self._clean_form() self._post_clean() def _clean_fields(self): self.fields是一个字典 for name, field in self.fields.items(): 循环自己的字段 # value_from_datadict() gets the data from the data dictionaries. # Each widget type knows how to retrieve its own data, because some # widgets split data over several HTML fields. if field.disabled: value = self.get_initial_for_field(field, name) 取值:request.POST.get('') else: field本质是正则表达式,根据正则表达式和输入的数据进行校验 value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) try: if isinstance(field, FileField): initial = self.get_initial_for_field(field, name) value = field.clean(value, initial) #根据字段的正则表达式和输入的数据进行校验 else: value = field.clean(value) self.cleaned_data[name] = value 如果验证通过,self.cleaned_data包含了用户提交过来并且验证成功的值 if hasattr(self, 'clean_%s' % name): self代指的就是那个TestForm对象 name就是字段名 clean_字段名 value = getattr(self, 'clean_%s' % name)() #clean开头,name结尾的字段, 加个括号执行函数 self.cleaned_data[name] = value except ValidationError as e:#抛出异常 self.add_error(name, e) #加到错误信息 hasattr:判断object中有没有一个name字符串对应的方法或属性,hasattr先判断有没有 getattr(object, name, default=None) 每一个字段来,先执行正则表达式,再执行函数 如果正则表达式没有通过,函数不会执行 return False return True target:提交之后的动作 from django.core.exceptions import ValidationError class TestForm(Form): user = fields.CharField(validators=[])#1 pwd = fields.CharField()#2 def clean_user(self):#3 v = self.cleaned_data['user'] if models.Student.objects.filter(name=v).count(): #如果验证数据成功了 # raise ValueError('用户名已经存在') raise ValidationError('用户名已经存在',code='invalid') #code='invalid' / 'required' 'max_length' 'min_length' return self.cleaned_data['user']#必须有返回值,否则返回None def clean_pwd(self):#4 return self.cleaned_data['pwd'] def clean(self): user = self.cleaned_data.get('user') email = self.cleaned_data.get('email') if models.Student.objects.filter(user=user,email=email).count(): #表示已经用户名已经存在 raise self.cleaned_data # return self.cleaned_data def _clean_form(self): try: cleaned_data = self.clean() #如果返回None则不会重新赋值 except ValidationError as e:#如果出错执行该语句 self.add_error(None, e) else: if cleaned_data is not None: #如果没出错执行该语句 self.cleaned_data = cleaned_data #重新赋值 def clean(self): #这个功能可以自定制 """ Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named '__all__'. """ Hook:钩子 return self.cleaned_data def _post_clean(self): """ An internal hook for performing additional cleaning after form cleaning is complete. Used for model validation in model forms. """ pass # 执行顺序:1-3-2-4
c. 扩展 - is_valid - 字段 = 默认正则表达式 - 额外的正则 from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class MyForm(Form): user = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], ) - clean_字段,必须返回值 - clean() 有返回值:cleaned_data = 返回值 无返回值:cleaned_data = 原来的值
1. 使用 class Foo: xx = xxxxxx() # 正则,插件 def clean_xx(): .. def clean(): pass 2. 页面展示 obj = Foo() obj = Foo(init..) # 灵活 <form> {{obj.xx}} {{obj.xx}} {{obj.xx}} {{obj.xx}} </form> # 简单 {{obj.as_p}} <ul> {{obj.as_ul}} </ul> <table> {{obj.as_table}} </table> 3. 后台 is_valid() clean_data errors 可以被JSON序列化 思考题: class Input: def init(self,attrs,value): self.attrs def __str__(): return <input values='x' />
文件上传功能
Form文件上传:
from django.core.files.uploadedfile import InMemoryUploadedFile def f1(request): if request.method == "GET": return render(request,'f1.html') else: # print(request.FILES)#输出对象<MultiValueDict: {}> #<MultiValueDict: {'fafafa': [<InMemoryUploadedFile: QQ图片20170210015937.gif (image/gif)>]}> # print(request.FILES.get('fafafa'))#输出对象 拿到字符串,而getlist拿到的是列表,文件内容 QQ图片20170210015937.gif # print(request.FILES.getlist('fafafa'))#输出对象InMemoryUploadedFile [<InMemoryUploadedFile: QQ图片20170210015937.gif (image/gif)>] file_obj = request.FILES.get('fafafa') # print(type(file_obj))#<class 'django.core.files.uploadedfile.InMemoryUploadedFile'> # print(file_obj.name) # print(file_obj.size) # f = open(file_obj.name,'wb') f = open(os.path.join('static',file_obj.name),'wb') for chunk in file_obj.chunks(): f.write(chunk) f.close() return render(request,'f1.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="POST" action="/f1/" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="fafafa"> <input type="submit" value="提交"> </form> </body> </html>
注意事项:
<form method="POST" action="/f2/" enctype="multipart/form-data"> {% csrf_token %} {{ obj.user }} {{ obj.fafafa }} <input type="submit" value="提交"> </form> form表单栏必须加这一句:enctype="multipart/form-data",否则上传不成功