1、CBV和FBV的用法
2、序列化用法
3、form表单
一、CBV和FBV
1、cbv是 class based view(基于类),fbv是function based view(基于函数)
2、cbv基于dispatch进行反射,get获取,post提交
3、应用场景:登录认证(继承dispatch,在dispatch里做session验证)
CBV第一种方式继承
1、单继承
扫盲:(继承的时候,一定要清楚self是哪个类实例化出来的对象,下例,self为B实例化的对象,任何属性优先从自己里面找,找不到在去父类里找)
class A(object): def aaa(self): print('from A') def bbb(self): self.aaa() class B(A): def aaa(self): print('from B') c = B() c.aaa()
from django.views import View class BaseView(View): def dispatch(self, request, *args, **kwargs): # 继承父类的dispatch,因为父类里有返回值,所以也要有return if request.session.get('username'): response = super(BaseView, self).dispatch(request, *args, **kwargs) return response else: return redirect('/login.html') class IndexView(BaseView): def get(self, request, *args, **kwargs): return HttpResponse(request.session['username'])
2、多继承(继承顺序从左到右)
class BaseView(object): def dispatch(self, request, *args, **kwargs): if request.session.get('username'): response = super(BaseView,self).dispatch(request, *args, **kwargs) return response else: return redirect('/login.html') class IndexView(BaseView,View):#先去找BaseView,BaseView中未定义在去找View def get(self,request,*args,**kwargs): return HttpResponse(request.session['username'])
CBV第二种方式装饰器
from django.utils.decorators import method_decorator def auth(func): #定义装饰器 def inner(request,*args,**kwargs): if request.session.get('username'): obj = func(request,*args,**kwargs) return obj else: return redirect('/login.html') return inner @method_decorator(auth,name='get') #放在类顶部就需要method_decorator这个装饰器 class IndexView(View): @method_decorator(auth) #放在dispatch上就相当于全局都需要经过认证 def dispatch(self, request, *args, **kwargs): if request.session.get('username'): response = super(IndexView,self).dispatch(request, *args, **kwargs) return response else: return redirect('/login.html') @method_decorator(auth) def get(self,request,*args,**kwargs): return HttpResponse(request.session['username']) @method_decorator(csrf_exempt) # 无效 csrf 放到post函数上的装饰器,是无效的,需要放到dispath上或者类上 def post(self,request,*args,**kwargs): return HttpResponse(request.session['username'])
特殊csrf
特殊:CSRF class IndexView(View): @method_decorator(csrf_exempt) #不能放属性上,只能放在全局 def dispatch(self, request, *args, **kwargs): return super(LoginView,self).dispatch(request, *args, **kwargs) def get(self,request,*args,**kwargs): return HttpResponse(request.session['username']) def post(self,request,*args,**kwargs): return HttpResponse(request.session['username'])
二、序列化
方式一 serialize,可以序列化对象
user_list = models.UserInfo.objects.all() data = serializers.serialize("json", user_list) [ {"model": "app01.userinfo", "pk": 1, "fields": {"username": "u5174u666e", "password": "123123"}}, {"model": "app01.userinfo", "pk": 2, "fields": {"username": "u94f6u79cbu826f", "password": "666"}} ]
方式二 json dumps(只能序列化python支持的数据类型)
user_list = models.UserInfo.objects.values('id','username') user_list = list(user_list) data = json.dumps(user_list) [ {"username": "u5174u666e", "id": 1}, {"username": "u94f6u79cbu826f", "id": 2} ]
json dumps不能序列化时间,通过自定义来支持序列化时间
import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self, field) user_list = [ {'id':1,'name':'alex','ctime': datetime.now()}, {'id':2,'name':'eric','ctime': datetime.now()} ] data = json.dumps(user_list,cls=JsonCustomEncoder) print(data) ''' [{"ctime": "2017-09-15 06:47:53", "id": 1, "name": "alex"}, {"ctime": "2017-09-15 06:47:53", "id": 2, "name": "eric"}] '''
三、Form表单验证
1、form表单的功能
表单验证和生成表单
示例:用户管理
a. 添加用户页面
- 显示HTML标签
- 提交:数据验证
- 成功之后保存
- 错误显示错误信息
创建Form类(本质就是正则表达式的集合)
from django.forms import Form from django.forms import fields from django.forms import widgets class UserForm(Form): username = fields.CharField( required=True, #默认就为true,可以不填 error_messages={'required':'用户名不能为空'}, #自定义错误信息 widget=widgets.TextInput(attrs={'class':'form-control'}) #额外自定义样式 ) password = fields.CharField( required=True, error_messages={'required': '邮箱不能为空','invalid':'邮箱格式错误'}, #邮箱的错误提示需要写在invalid里 widget = widgets.TextInput(attrs={'class': 'form-control'}) ) # fields.EmailField() # fields.GenericIPAddressField(protocol='ipv4') ut_id = fields.ChoiceField( #单选和多选会有个下拉框内容填充的问题,默认类的属性只加载一次,需要通过构造方法,使得每次调用都更新一次 choices=[], widget=widgets.Select(attrs={'class':'form-control'}) ) role_id = fields.MultipleChoiceField( choices=[], widget=widgets.SelectMultiple(attrs={'class':'form-control'}) ) def __init__(self,*args,**kwargs): super(UserForm,self).__init__(*args,**kwargs) # self.fields已经有所有拷贝的字段 self.fields['ut_id'].choices = models.UserType.objects.values_list('id','title') self.fields['role_id'].choices = models.Role.objects.values_list('id','caption')
例子添加用户:
view里
from django.forms import Form,fields,widgets class UserForm(Form): '''用户表单''' username = fields.CharField(required=True,error_messages={'required':'用户名不能为空'}) password = fields.CharField(required=True,error_messages={'required':'密码不能为空'}) # ip = fields.GenericIPAddressField(required=True,error_messages={'required':'IP不能为空','invalid':'IP格式错误'}) ut_id = fields.ChoiceField(choices=[]) def __init__(self,*args,**kwargs): super(UserForm,self).__init__(*args,**kwargs) self.fields['ut_id'].choices = models.UserType.objects.values_list('id','title')
class AddUserView(AuthView,View): '''添加视图''' def get(self,request,*args,**kwargs): form = UserForm() return render(request,'add_user.html',{'form':form}) def post(self,request,*args,**kwargs): form = UserForm(request.POST) if form.is_valid(): print(form.cleaned_data) models.UserInfo.objects.create(**form.cleaned_data) return redirect('/users.html') else: print(form.errors) return render(request,'add_user.html',{"form":form})
tempelate:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>添加用户</h1> <form method="POST" novalidate> {% csrf_token %} <p> 用户名: {{ form.username }} {{ form.errors.username.0 }} </p> <p> 密码: {{ form.password }} {{ form.errors.password.0 }} </p> {# <p>#} {# ip: {{ form.ip }} {{ form.errors.ip.0 }}#} {# </p>#} <p> 用户类型: {{ form.ut_id }} {{ form.errors.ut_id.0 }} </p> <input type="submit" value="提交"> </form> </body> </html>
知识点:form(request.POST),将request内的数据传递给from表单,form表单会进行正则验证,通过obj.is_valid(), 如果正常, 返回值就是obj.cleaned_data,如果出现异常,异常信息会以字典形式存放在obj.errors 。一个输入框多条错误信息 一般只取第一条错误信息,处理完这一条在去处理其他
带默认值的添加标签:
class EditUserView(AuthView,View): def get(self,request,pk): obj = models.UserInfo.objects.filter(id=pk).first() role_id_list = obj.rl.values_list('id') v = list(zip(*role_id_list))[0] if role_id_list else [] form = UserForm(initial={'username': obj.username, 'password': obj.password, 'ut_id': obj.ut_id,'role_id':v}) return render(request,'edit_user.html',{'form':form}) def post(self,request,pk): form = UserForm(data=request.POST) if form.is_valid(): # # {'username': 'xxxxx', 'password': 'xxxxx', 'ut_id': '1',role_id:} role_id = form.cleaned_data.pop('role_id') # 用户表更新 query = models.UserInfo.objects.filter(id=pk) query.update(**form.cleaned_data) obj = query.first() obj.rl.set(role_id) return redirect('/users.html') else: print(form.errors) return render(request, 'edit_user.html', {'form': form})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>编辑用户</h1> <form method="POST" novalidate> {% csrf_token %} <p> 用户名: {{ form.username }} {{ form.errors.username.0 }} </p> <p> 密码: {{ form.password }} {{ form.errors.password.0 }} </p> {# <p>#} {# ip: {{ form.ip }} {{ form.errors.ip.0 }}#} {# </p>#} <p> 用户类型: {{ form.ut_id }} {{ form.errors.ut_id.0 }} </p> <input type="submit" value="提交"> </form> </body> </html>
通过ajax+form表单验证,实现注册功能
view:
class RegisterForm(Form): user = fields.CharField(required=True,min_length=6,max_length=18) email = fields.EmailField(required=True,min_length=6,max_length=18) password = fields.CharField(min_length=12) import json def register(request): if request.method == 'GET': form = RegisterForm() return render(request,'register.html',{'form':form}) else: response = {'status': True,'data': None,'msg':None} form = RegisterForm(request.POST) if form.is_valid(): print(form.cleaned_data) # 数据库中添加一条数据 # return redirect('/login.html') # ajax跳转,错错错 else: response['status'] = False response['msg'] = form.errors return HttpResponse(json.dumps(response))
tempelate
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id="f1"> {% csrf_token %} <p>用户名:{{ form.user }}</p> <p>密码:{{ form.password }}</p> <p>邮箱:{{ form.email }}</p> <input type="button" value="提交" onclick="submitForm();" /> </form> <script src="/static/jquery-3.2.1.js"></script> <script> function submitForm() { $('#f1 .error').remove(); $.ajax({ url: '/register.html', type: 'POST', data: $('#f1').serialize(), dataType: 'JSON', success:function (arg) { if(arg.status){ location.href = "/login.html"; }else{ /* arg.msg = { email: ['xxxxx',] password: ['xxxxx',] user: ['xxxxx',] } */ $.each(arg.msg,function (k,v) { var tag = document.createElement('span'); tag.innerHTML = v[0]; tag.className = "error"; // <span class='error'>v[0]</span> $('#f1 input[name="'+k+'"]').after(tag); }) } } }) } </script> </body> </html>