python自动化开发-[第二十天]-form表单,CBV和FBV,序列化

时间:2024-01-02 14:12:14

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": "\u5174\u666e", "password": "123123"}},
{"model": "app01.userinfo", "pk": 2, "fields": {"username": "\u94f6\u79cb\u826f", "password": "666"}}
]

 方式二 json dumps(只能序列化python支持的数据类型)

user_list = models.UserInfo.objects.values('id','username')
user_list = list(user_list)
data = json.dumps(user_list)
[
{"username": "\u5174\u666e", "id": 1},
{"username": "\u94f6\u79cb\u826f", "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>