s14_示例:Form操作
- 示例(数据库操作补充之QuerySet方法、 Model数据验证以及钩子、动态Select数据、Form内置钩子、Django序列化)
# urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', test.index),
url(r'^login.html$', account.login),
url(r'^register/', test.register),
]
# views/test.py
from django.shortcuts import render,HttpResponse
# Create your views here.
from app01 import models
def index(request):
# models.UserType.objects.all().values('name','user__pwd')
# models.UserInfo.objects.create(name='root',email='root')
# 没有进行验证
# obj = models.UserInfo(name='alex',email='alex')
# obj.full_clean() # 验证
# obj.save()
# 此方法会验证
from app01.forms import UserInfoForm
if request.method == 'GET':
obj = UserInfoForm()
# obj = UserInfoForm({'user':'alex'})
# obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
return render(request, 'index.html',{'obj':obj})
elif request.method=='POST':
obj = UserInfoForm(request.POST,request.FILES)
obj.is_valid()
def register(request):
from app01.forms import RegisterForm
from django.core.exceptions import NON_FIELD_ERRORS
# obj =RegisterForm(request.POST)
# if obj.is_valid():
# obj.cleaned_data
# else:
# obj.errors
# {
# '__all__':[],
# # 'NON_FIELD_ERRORS':[],
# # 整体错误信息在__all__里面
# 'user':[{'code':'required','message':'xxx'}],
# 'pwd':[{'code':'required','message':'xxx'}],
# }
# djang 默认序列化
# from django.core import serializers
# ret = models.UserType.objects.all()
# data = serializers.serialize("json", ret)
# return HttpResponse(data)
# 自定制
import json
v = models.UserType.objects.values_list('id','name')
v=list(v)
return HttpResponse(json.dumps(v))
# views/account.py
from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields
from django.forms import widgets
import json
class LoginForm(forms.Form):
# 登陆
username = fields.CharField()
password = fields.CharField(
max_length=64,
min_length=12,
)
from django.core.exceptions import ValidationError
class JsonCustomEncoder(json.JSONEncoder):
def default(self, field):
if isinstance(field,ValidationError):
return {'code':field.code,'message':field.messages}
else:
return json.JSONEncoder.default(self,field)
def login(request):
ret = {'status':True,'error':None,'data':None}
if request.method=='GET':
return render(request,'login.html')
elif request.method=='POST':
obj = LoginForm(request.POST)
if obj.is_valid():
print(obj.clean_data)
else:
# print(obj.errors,type(obj.errors))
# ret['error'] = obj.errors.as_json()
# 前端需要对 arg parse两回才能得到error
from django.forms.utils import ErrorDict
print(type(obj.errors.as_data()))
for k,v in obj.errors.as_data().items():
print(k,v)
from django.core.exceptions import ValidationError
ret['error'] =obj.errors.as_data()
result =json.dumps(ret,cls=JsonCustomEncoder)
return HttpResponse(result)
# models.py
from django.db import models
# Create your models here.
class UserType(models.Model):
name=models.CharField(max_length=32)
def __str__(self):
return self.name
class User(models.Model):
user =models.CharField(max_length=32)
pwd =models.CharField(max_length=64)
ut = models.ForeignKey(to='UserType',
to_field='id',
related_name='b',
related_query_name='a',
limit_choices_to={'id__gt':5}, # admin 中外键筛选
# parent_link=False #欠着
)
# 正向查找
# v = User.objects.all()
# for item in v:
# item.user
# item.pwd
# item.ut.name
# User.objects.all().values('user','ut__name')
# 反向查找
# v= UserType.objects.all()
# for item in v:
# item.name
# item.id
# item.user_set.all()
# related_name='b' ==> item.b.all()
# related_query_name='a' ==> item.a_set.all()
# UserType.objects.all().values('name','user__pwd')
class Blog(models.Model):
site = models.CharField(max_length=32)
m =models.ManyToManyField('Tag',through='B2T',through_fields=['b','t1'])
class Tag(models.Model):
name = models.CharField(max_length=32)
class B2T(models.Model):
b = models.ForeignKey('Blog')
t1 = models.ForeignKey('Tag')
# t2 = models.ForeignKey('Tag')
class UserInfo(models.Model):
name=models.CharField(max_length=32)
email = models.EmailField()
# 预留的方法
def clean(self):
from django.core.exceptions import ValidationError
c = UserInfo.objects.filter(name=self.name).count()
if c:
# 主动报错
raise ValidationError(message='用户名已经存在',code='i1')
# login.html
<form id="fm">
{% csrf_token %}
<p><input type="text"name="username"></p>
<p><input type="password"name="password"></p>
<p><a id = 'submit'>提交</a></p>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script>
$(function () {
$('#submit').click(function () {
$.ajax({
url:'/login.html',
type:'POST',
data:$('#fm').serialize(),
//自行打包了csrf_token
success: function (arg) {
console.log(arg);
arg = JSON.parse(arg);
console.log(arg);
},
error: function () {
}
})
})
});
</script>
# forms.py
from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms.models import ModelChoiceField,ModelMultipleChoiceField
from app01 import models
class UserInfoForm(forms.Form):
user = fields.CharField(
required= False,
widget=widgets.Textarea(attrs={'class':'c1'})
)
pwd =fields.CharField(
max_length= 12,
widget= widgets.PasswordInput(attrs={'class':'c1'})
)
user_type = fields.ChoiceField(
# choices=[(1,'普通用户'),(2,'超级用户')],
# choices=models.UserType.objects.values_list('id','name'),
# 增加后无法更新,静态字段
choices=[],
widget = widgets.Select
)
user_type2 = fields.CharField(widget=widgets.Select(choices=[]))
# 解决方法二
user_type3 = ModelChoiceField(
empty_label='请选择用户类型',
queryset=models.UserType.objects.all(),
to_field_name='id'
# 依赖 models.py中的 def __str__(self): return self.name
# 否则选项的是对象
)
# 解决方法一(推荐)
def __init__(self,*args,**kwargs):
# 自定义方法,重新获取
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')
# 验证:
# 生成html(保留上一次提交的数据)
# 新URL方式操作(Form方式)
# Ajax请求通常不使用Form生成html,只使用验证。
from django.core.exceptions import ValidationError
class RegisterForm(forms.Form):
user =fields.CharField()
email =fields.EmailField()
# 单独字段
def clean_user(self):
c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count()
if not c:
return self.cleaned_data['user']
else:
raise ValidationError('用户名已经存在',code='xxx')
def clean_email(self):
return self.cleaned_data['email']
class LoginForm(forms.Form):
user =fields.CharField()
pwd =fields.CharField()
# 需整体显示错误信息(用户名是否存在)
def clean_user(self):
c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count()
if not c:
return self.cleaned_data['user']
else:
raise ValidationError('用户名已经存在',code='xxx')
def clean_pwd(self):
return self.cleaned_data['pwd']
def clean(self):
c = models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
if c:
return self.clean_data
else:
raise ValidationError('用户名或密码错误')
# 密码两次输入一致,可在此判断
def _post_clean(self):
pass
#index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p>{{ obj.user }}</p>
<p>{{ obj.pwd }}</p>
<p>{{ obj.user_type }}</p>
<p>{{ obj.user_type2 }}</p>
<p>{{ obj.user_type3 }}</p>
</body>
</html>