django Form高级(二)

 

一、Choice字段需要重启启动服务才能更新的原因:

1.index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action='/index/' method="post">
        {% csrf_token %}
        <p>{{ obj.user }}</p>
        <p>{{ obj.pwd }}</p>
        <p>{{ obj.user_type }}</p>
        <input type="submit" value="提交">
    </form>
</body>
</html>
2.forms.py
from django import forms
from django.forms import fields,widgets
from app01 import models
class UserInfoForm(forms.Form):
    #Form有两个功能:
    #1.验证
    #2.生成Html
    #在新URL方式操作的时候,生成Html,在Ajax提交请求的时候,不需要生成Html

    user = fields.CharField(
        required=False,
        widget = widgets.Textarea(attrs={'class':'c1'})
    )
#字段不能同步更新的原因: #user为类变量(静态字段),静态字段是属于类的,
程序加载的时候,类中的静态字段一次性加载到内 # 在
    # def __init__(self,age): 
# self.age
= age
# self.age为字段,为实例变量,程序加载的时候并不执行,只有在实例化的时候才执行。

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')
)
3.views.py
from django.shortcuts import render,redirect,HttpResponse
from app01.forms import UserInfoForm
def index(request):
obj
= UserInfoForm()
return render(request,'index.html',{'obj':obj})

4.models.py
from django.db import models
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')
class UserType(models.Model):
name
=models.CharField(max_length=32)
def __str__(self):
return self.name

#以上实例中用户类型字段中现有(“普通用户”,“超级用户”),如果在此字段添加"游客"字段后,前台并不能马上进行更新,需要重新启动服务才能更新

实现同步更新前台数据方法:

 

方法一:
user_type = fields.ChoiceField(
#choices=[(1,'普通用户'),(2,'超级用户'),]
#choices=models.UserType.objects.values_list('id','name')
choices=[],
widget=widgets.Select
)

#对应的forms.py中的初始化方法,对models.py没有要求:
def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
方法二:
user_type2= fields.CharField(widget=widgets.Select(choices=[]))

#对应的forms.py中的初始化方法,对models.py没有要求:
def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields['user_type2'].widget.choices=models.UserType.objects.values_list('id','name')

方法三:
from django.forms.models import ModelChoicefield
user_type3 = ModelChoiceField(
empty_label = "请选择用户类型"
queryset = models.UserType.objects.all()
#其它参数
#queryset 查询数据库中的数据
#empty_label="--------" 默认空显示内容
#to_field_name = Noe #HTML中value的值对应的字段 option字段中的value值
#limit_choices_to = NOne #ModelForm中对queryset二次筛选
)
#无需在forms.py中进行初始化,但models.py中需要以字符串返回:
class UserType(models.Model):
name=models.CharField(max_length=32)

def __str__(self):
return self.na

事例如下:

1
.views.py
from django.shortcuts import render,redirect,HttpResponse
from app01.forms import UserInfoForm from app01 import models def index(request): #方法一 每次刷新页面都进行实例化: obj = UserInfoForm() #如果加上,则显示值,如 obj = UserInfoForm('user':"zhangsan") obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name') #'id在前',option选项中的value值为id,如果name在前,option选项中的value值则为name
    print(obj.fields)
#以上操作是在实例化后进行的操作,也就是每次刷新页面后对重新进行实例化 #OrderedDict([(
'user', <django.forms.fields.CharField object at 0x110f1b7b8>), ('pwd', <django.forms.fields.CharField object at 0x110f862e8>), ('user_type', <django.forms.fields.ChoiceField object at 0x110f863c8>)])
#fields字段中包含三个字段('user','pwd','user_type'
),当每次程序加载的时候 #程序都会对类进行一次深拷贝,因此如果要对字段进行同步更新修改修改 def __init__(self)初始化函数, # #方法二 重写构造方法: #修改forms.py文件,添加如下内容: #def __init__(self, *args, **kwargs): # super(UserInfoForm, self).__init__(*args, **kwargs) # self.fields['user_type'].choices = models.UserType.objects.values_list('id', 'name') #'id在前',option选项中的value值为id,如果name在前,option选项中的value值则为name obj = UserInfoForm() return render(request,'index.html',{'obj':obj}) #方法三,因为choice在forms中的声明方法不同 2.index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action='/index/' method="post"> {% csrf_token %} <p>{{ obj.user }}</p> <p>{{ obj.pwd }}</p> <p>{{ obj.user_type }}</p> #方法一 <p>{{ obj.user_type2 }}</p> #方法二
<p>{{ obj.user_type2 }}</p> #方法三
<input type="submit" value="提交"> </form> </body> </html> 

3.forms.py

from django import forms

from django.forms import fields,widgets

from app01 import models

class UserInfoForm(forms.Form):
#Form有两个功能:
#
1.验证
#2
.生成Html
#在新URL方式操作的时候,生成Html,在Ajax提交请求的时候,不需要生成Html
user
= fields.CharField(
required
=False,
widget
= widgets.Textarea(attrs={'class':'c1'}) )
#user为类变量(静态字段),静态字段是属于类的
# def __init__(self,age):
# self.age
= age
# self.age为字段,为实例变量,只有在实例化的时候才执行。
#程序加载的时候,类中的静态字段一次性加载到内存
pwd
= fields.CharField(
max_length
=32,
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=[])) #方法二
 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') #方法二

4.models.py

from django.db import models

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') class UserType(models.Model): name=models.CharField(max_length=32) def __str__(self): return self.name 5.urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]

 

二、Form操作---钩子

1.views.py

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__':[]  #整体错误信息  clean方法的错误信息
        #   'NON_FIELD_ERRORS':[]
        #    'NON_FIELD_ERRORS' = '__all__'
        #   'user':[{'code':'required','message':'xxx'}]  clean_user
        #   'pwd':[{'code':'required','message':'xxx'}]   clean_pwd
      
2.forms.py

from django.core.exceptions import ValidationError
#对单独字段的钩子
class RegisterForm(forms.Form):
    user=fields.CharField()
    email=fields.EmailField()

    #执行顺序,首先验证user的正则表达式,如果正则表达式通过了,执行clean_user方法
    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):
        pass
    def clean_pwd(self):
        pass

    def clean(self):
        c= models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
        if c:
            return self.cleaned_data
        else:
            raise  ValidationError('用户名或密码错误')


    def _post_clean(self):
        pass
3.models.py
from django.db import models

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')

class UserType(models.Model):
    name=models.CharField(max_length=32)

    def __str__(self):
        return self.name

4.index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action='/index/' method="post">
        {% csrf_token %}
        <p>{{ obj.user }}</p>
        <p>{{ obj.pwd }}</p>
        <p>{{ obj.user_type }}</p>
        <p>{{ obj.user_type2 }}</p>
        <p>{{ obj.user_type3 }}</p>
        <input type="submit" value="提交">
    </form>
</body>
</html>
5.urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),

]

 三、序列化

一)错误信息序列化:

1.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,'messages':field.messages}

        else:
            return json.JSONEncoder.default(self,field)

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method=='POST':
       ret = {'status':True,'error':None,'data':None}
       obj= LoginForm(request.POST)
       if obj.is_valid():
           print("obj.cleaned_data:",obj.cleaned_data)
           #obj.cleaned_data: {'password': '12222222222222', 'username': 'jidi'}
       else:
           #print("obj.errors",obj.errors)
           #obj.errors <ul class="errorlist"><li>password<ul class="errorlist"><li>Ensure this value has at least 12 characters (it has 3).</li></ul></li></ul>
           #print(type(obj.errors))
           for k,v in obj.errors.as_data().items():
               print(k,v)
           #username [ValidationError(['This field is required.'])]    ---->虽然as_data序列化后是字典,但字典内的值为ValidationError,json不能对其进行序列化
           #password [ValidationError(['Ensure this value has at least 12 characters (it has 9).'])]
           from django.core.exceptions import ValidationError
           #<class 'django.forms.utils.ErrorDict'>
           #from django.forms.utils import ErrorDict
           #继承了字典,包括几个函数:
           #1.as_data   ---->把字段转换成字典
           #2.as_json   ---->把字段转换成字符串
           #3.as_ul     ---->把字段转换成html
           #4.as_text   ---->把字段转换成文本

           #ret['error'] = obj.errors.as_json()
           #js的console中输出:
           # {"error": "{\"password\": [{\"message\": \"Ensure this value has at least 12 characters (it has 9).\", \"code\": \"min_length\"}]}", "data": null, "status": true}
           #把最终的字符串error付值给ret
           #a = obj.errors.as_text()
           #print("a:",a)
           #a: * password
           # * Ensure this value has at least 12 characters (it has 9).
           #b = obj.errors.as_ul()
           #print("b:",b)
           #b: <ul class="errorlist"><li>password<ul class="errorlist"><li>Ensure this value has at least 12 characters (it has 9).</li></ul></li></ul>
           #c = obj.errors.as_data()
           #print("c:",c)
           #c: {'password': [ValidationError(['Ensure this value has at least 12 characters (it has 9).'])]}
           ret['error'] = obj.errors.as_data()
    result = json.dumps(ret,cls=JsonCustomEncoder)
    print(result)
    #{"error": {"password": [{"messages": ["Ensure this value has at least 12 characters (it has 9)."], "code": "min_length"}], "username": [{"messages": ["This field is required."], "code": "required"}]}, "status": true, "data": null}

    return HttpResponse(result)
    #json.dupms 序列化成字符串

2.login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm">
        {% csrf_token %}
        <p><input type="text" name="username"></p>
        <p><input type="password" name="password"></p>
        <a id="submit">提交</a>
    </form>
    <script src="/static/jquery.min.js"></script>
    <script>
        $(function(){
            $('#submit').click(function(){
                $.ajax({
                    url:'/login.html',
                    type:'POST',
                    data:$('#fm').serialize(),
                    success:function(arg){
                        console.log(arg);  //返回字符串
                        //{"data": null, "status": true, "error": "{\"password\": [{\"message\": \"Ensure this value has at least 12 characters (it has 9).\", \"code\": \"min_length\"}]}"}
                        arg = JSON.parse(arg);
                        //把字符串转换成对像
                        //console.log(arg);
                        //Object {data: null, status: true, error: "{"password": [{"message": "Ensure this value has a… characters (it has 9).", "code": "min_length"}]}"}
                        //arg.error = JSON.parse(arg.error);
                        //把arg对象中的error字符串转化为对象
                        //console.log(arg);
                        //Object {data: null, status: true, error: Object}
                    },
                    error:function(){

                    }
                })
            })
        })
    </script>
</body>
</html>

3.forms.py
from django import forms
from django.forms import fields,widgets
from app01 import models
from django.forms.models import ModelChoiceField

class UserInfoForm(forms.Form):
    #Form有两个功能:
    #1.验证
    #2.生成Html
    #在新URL方式操作的时候,生成Html,在Ajax提交请求的时候,不需要生成Html

    user = fields.CharField(
        required=False,
        widget = widgets.Textarea(attrs={'class':'c1'})
    )
    #user为类变量(静态字段),静态字段是属于类的
    # 在
    # def __init__(self,age):
    #       self.age = age
    #  self.age为字段,为实例变量,只有在实例化的时候才执行。
    #程序加载的时候,类中的静态字段一次性加载到内存
    pwd = fields.CharField(
        max_length=32,
        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= "请选择用户类型",
        to_field_name= 'name',
        queryset = models.UserType.objects.all()
    )
    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')



from django.core.exceptions import ValidationError
#对单独字段的钩子
class RegisterForm(forms.Form):
    user=fields.CharField()
    email=fields.EmailField()

    #执行顺序,首先验证user的正则表达式,如果正则表达式通过了,执行clean_user方法
    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(self):
        c= models.UserInfo.objects.filter(
name=self.cleaned_data['user'],
pwd=self.cleaned_data['pwd']).count() if c: return self.cleaned_data else: raise ValidationError('用户名或密码错误') def _post_clean(self): pass 4.urls.py from django.conf.urls import url from django.contrib import admin from app01.views import test,account urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', test.index), url(r'^login.html$', account.login), ]

二)对Queryset序列化:

第一种:
  from django.core import serializers

  v = models.tb.objects.all()     #---->返回对象,使用serizlizers进行序列化
  data = serializers.serialize("json",v)


第二种:
   v = models.tb.objects.values('id','name') #---->返回为字典,然后转化成列表进行序列化
   v = list(v)
   v = json.dumps(v)


  #如果返回对象中有datetime,则需使用JSONEncoder进行序列化
  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)
  v = models.tb.objects.values('id','name','ctime')
  v = list(v)
  v = json.dumps(v,cls=JsonCustomEncoder)
)

 

posted @ 2017-04-26 15:27  jidi_78  阅读(86)  评论(0)    收藏  举报