27)django-form操作示例(動態Select數據,自定義字段驗證,全局驗證等)


1)普通傳遞select數據

    # -*- coding:utf-8 -*-
    __author__ = 'shisanjun'
    
    from django import forms
    from django.forms import fields,widgets
    
    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,"超級用戶")], widget=widgets.Select, ) <form action='{% url "index" %}' method="post">
        <p>
            {{ obj.user }}
        </p>
        <p>{{ obj.pwd }}</p>
        <p>{{ obj.user_type }}</p>
    </form>

2)上面choice應該從數據庫中取數據

from django import forms
from django.forms import fields,widgets
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.all().values_list("id","name"),#要返回元組列表 widget=widgets.Select, )


3)上面有個問題,就是數據庫中新增加的數據,需要重起服務才能加載新數據。

這是什么原因造成的?
上面user,pwd,user_type都是放在類里面的,都是靜態字段,數據加載都是一次性加載在內存里面的。


#解決:
def index(request):
    from app01 import forms
    obj=forms.UserInfoForm()
    obj.fields#這里面封裝了user,pwd,user_type,當數據庫有新的數據的時候從新賦值
    obj.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
    return render(request,"index.html",{"obj":obj})

4)上面如果有很多choince,那要寫很多,怎么改進(兩種方法)

重新構造form的__init__()方法。在init里面賦值上面也是對類對象的實例重新賦值。


#方法1
# -*- coding:utf-8 -*-
__author__ = 'shisanjun'

from django import forms
from django.forms import fields,widgets
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.all().values_list("id","name"),
        widget=widgets.Select,
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")

#方法2


 -*- coding:utf-8 -*-
__author__ = 'shisanjun'

from django import forms
from django.forms import fields,widgets
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"})
    )
  #方法1 user_type=fields.ChoiceField( #choices=[(1,"普通用戶"),(2,"超級用戶")], choices=[],#這里不用賦值,原因實例化的時候init會賦值 widget=widgets.Select, ) #方法2 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.all().values_list("id","name") #方法2 self.fields["user_type2"].widget.choices=models.UserType.objects.all().values_list("i
d","name")

5)上面從數據庫取數據也django也可以自己做,但是不太好。

from django.forms.models import ModelChoiceField
user_type3=ModelChoiceField(
        queryset=models.UserType.objects.all(),#django會自動取
    )

這里是有代價的,要在model里面加__str__,不然顯示的名稱是對象
class UserType(models.Model):
    name=models.CharField(max_length=32)
    def __str__(self):
        return self.name



# -*- coding:utf-8 -*-
__author__ = 'shisanjun'

from django import forms
from django.forms import fields,widgets
from app01 import models
from django.forms.models import ModelChoiceField
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=[],#這里不用賦值,原因實例化的時候init會賦值
        widget=widgets.Select,
    )
    #方法2
    user_type2=fields.CharField(widget=widgets.Select(choices=[]))

 #方法3 user_type3=ModelChoiceField( empty_label="請選擇", queryset=models.UserType.objects.all(),#django會自動取 )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
      #方法2
        self.fields["user_type2"].widget.choices=models.UserType.objects.all().values_list("id","name")

6)默認值

def index(request):
    from app01 import forms
    obj=forms.UserInfoForm()#如果這里賦值字典就是顯示默認值(初始化) obj.fields#這里面封裝了user,pwd,user_type,當數據庫有新的數據的時候從新賦值
    #obj.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
    return render(request,"index.html",{"obj":obj})

7)用戶驗證

def index(request):
    if request.method=="GET":
        obj=forms.UserInfoForm()#如果這里賦值字典就是顯示默認值(初始化)
        obj.fields#這里面封裝了user,pwd,user_type,當數據庫有新的數據的時候從新賦值
        #obj.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
        return render(request,"index.html",{"obj":obj})
    elif request.method=="POST":
        obj=forms.UserInfoForm(request.POST,request.FILES)
        obj.is_valid()#他是基於什么驗證的,根據from模板驗證。form會為長度,為空等驗證,但是如果用戶已存在,就不應該進行上面驗證。



    # -*- coding:utf-8 -*-
__author__ = 'shisanjun'

from django import forms
from django.forms import fields,widgets
from app01 import models
from django.forms.models import ModelChoiceField
from django.core.exceptions import ValidationError
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=[],#這里不用賦值,原因實例化的時候init會賦值
        widget=widgets.Select,
    )
    #方法2
    user_type2=fields.CharField(widget=widgets.Select(choices=[]))

    #方法3
    user_type3=ModelChoiceField(
         empty_label="請選擇",
        queryset=models.UserType.objects.all(),#django會自動取
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
      #方法2
        self.fields["user_type2"].widget.choices=models.UserType.objects.all().values_list("id","name")



class RegiesterForm(forms.Form):
    user=fields.CharField()#一個字段一個字段的循環,這里通過了,才會到clean_user,下面以次類推
    email=fields.EmailField()

 def clean_user(self): #通過調用form預留的鈎子,clean_user單獨對user做驗證 c=models.Userinfo.objects.filter(name=self.cleaned_data['user']) #如果數據庫中有,應該給頁面報錯了,顯示用戶已存在 if not c: return self.cleaned_data['user'] #返回原來值 else: #如果沒有拋出valideionError raise ValidationError("用戶名已存在",code="xxx")
    def clean_email(self):
        pass
    

8)如果用戶名不對,錯誤顯示在用戶名旁邊。(上面是單獨給字段寫的鈎子),也可以對整個form做鈎子驗證。

class LoginForm(forms.Form):
    user=fields.CharField()#一個字段一個字段的循環,這里通過了,才會到clean_user,下面以次類推
    pwd=fields.CharField()
    email=fields.EmailField()

    def clean_user(self): #通過調用form預留的鈎子,clean_user單獨對user做驗證
        c=models.Userinfo.objects.filter(name=self.cleaned_data['user'])
        #如果數據庫中有,應該給頁面報錯了,顯示用戶已存在
        if not c:
            return self.cleaned_data['user'] #返回原來值
        else:
            #如果沒有拋出valideionError
             raise ValidationError("用戶名已存在",code="user")
    def clean_email(self):
        pass

 def clean(self): #對整體驗證 #判斷用戶名和密碼是否存在 c= models.Userinfo.objects.filter(user=self.cleaned_data["user"],password=self.cleaned_data["pwd"]) if not c: return self.cleaned_data #源碼中self.cleaned_data=cleaned_data else: raise ValidationError("用戶名或密碼錯誤") 

源碼中一共有3個鈎子

self._clean_fields()對字段驗證
self._clean_form()對整體驗證
self._post_clean()

form驗證經歷階段:數據來了-->到相應的form-->先拿到第一個字段,先進行正則表達式判斷完,然后執行字段的鈎子,--〉所有字段運行完了到clean(),最后到postclean()

is_valid()--->self.errors-->full_clean -->  self._clean_fields()對字段驗證
                                            self._clean_form()對整體驗證
                                            self._post_clean()

views中錯誤信息

#views.py
def register(request):
    obj=forms.RegiesterForm(request.POST)
    if obj.is_valid(): #下面操作,可以在is_valid做驗證
        #obj.cleaned_data['']
        obj.cleaned_data()
    else:
        obj.errors
        #obj.errors就是個字段,每個字段的錯誤放在各自的字段里面,整體clean錯誤放在那里了
        from django.core.exceptions import NON_FIELD_ERRORS
        """
        '__all__':[],整體的錯誤信息clean拋出的異常都在這里==〉NON_FIELD_ERRORS
        NON_FIELD_ERRORS:[],
        'user':['code':required,'message':'xxx'],
        'pwd':['code':required,'message':'xxx'],

   """


account.py
from django.shortcuts import redirect,render,HttpResponse
from django import forms
from django.forms import fields
from django.forms import widgets
from app01 import models
from django.core.exceptions import ValidationError
import json
class LoginForm(forms.Form):
    user=fields.CharField()#一個字段一個字段的循環,這里通過了,才會到clean_user,下面以次類推
    pwd=fields.CharField()
    email=fields.EmailField()

    def clean_user(self): #通過調用form預留的鈎子,clean_user單獨對user做驗證
        c=models.Userinfo.objects.filter(name=self.cleaned_data['user'])
        #如果數據庫中有,應該給頁面報錯了,顯示用戶已存在
        if not c:
            return self.cleaned_data['user'] #返回原來值
        else:
            #如果沒有拋出valideionError
            raise  ValidationError("用戶名已存在",code="user")
    def clean_email(self):
        pass
    #
    # def clean(self): #對整體驗證
    #
    #     #判斷用戶名和密碼是否存在
    #     c= models.Userinfo.objects.filter(user=self.cleaned_data["user"],password=self.cleaned_data["pwd"])
    #     if not c:
    #         return self.cleaned_data #源碼中self.cleaned_data=cleaned_data
    #     else:
    #          ValidationError("用戶名或密碼錯誤")

class JsonCustomEncoder(json.JSONEncoder): from django.core.exceptions import ValidationError 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):
    res={"status":False,"data":None,"error":None}
    if request.method=="GET":
        return render(request,"login.html")
    elif request.method=="POST":
        obj=LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            res["status"]=True
        else:
            #res["error"]=obj.errors.as_json()
            #為什么不用as_json,as_json返回的是字典,所以res就會變成嵌套字典,json不能轉嵌套字典,下面用as_data()結合cls定制
            #print(obj.errors.as_data())#errors.as_data()返回的是 ValidationError類型,不是字典,不能直接序列化
            res["error"]=obj.errors.as_data()
        result=json.dumps(res,cls=JsonCustomEncoder)#dumps有個參數cls,可以定制

        return HttpResponse(json.dumps(result))

#obj.errors返回的是ErrorDict,不是字典(雖然繼承字典) #obj.errors.as_json() 返回的字符串(前端要連續反解兩次) #obj.errors.as_data() 返回原生的字典 但是返回value 是ValidationError,不能直接序列化
模板
<!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="text" name="password">
        </p>
        <a id="submit">提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function(){
            //框架自加載
            $("#submit").click(
                    function(){
                        $.ajax(
                                {
                                    url:"{% url 'login' %}",
                                    type:"post",
                                    data:$("#fm").serialize(),
                                    success:function(arg){
                                        arg=JSON.parse(arg);
                                        console.log(arg);
                                    },
                                    error:function(arg){
                                        console.log(arg);
                                    }

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM