django forms.ModelForm验证问题

时间:2011-04-11 10:23:25

标签: django validation django-forms

我有一些带有某些字段的模型。

我有一个模型表单,代表上述模型的一部分。我必须做一些自定义验证。有些领域依赖于其他领域。例如,密码和密码确认字段必须相同。它与后端系统联系在一起。

我必须检查登录名(确保它不在后端系统中,而不是在该项目的数据库中)。我必须验证长度等等。

然后我必须根据后端设置的约束来验证密码。我需要为此使用API​​。我必须使用密码传递登录名以使用此命令(它很傻但我不能改变它。)

如果登录名在其方法中引发验证错误,则密码验​​证methid不能使用sel.cleaned_data ['login']

这是代码。

class PEMUserDetails(models.Model):
    #Keys and IDs
    domain = models.OneToOneField('GIBOSite', primary_key=True)
    domain_name = models.CharField(unique=True, max_length=100)
    # Details
    PEM_login_id = models.CharField(max_length=32, unique=True)
    PEM_password = models.CharField(max_length=32)
    PEM_password_confirm = models.CharField(max_length=32)
    FTP_login = models.CharField(max_length=32, blank=True, null=True)
    FTP_password = models.CharField(max_length=32, blank=True, null=True)
    FTP_host_name = models.CharField(max_length=256, blank=True, null=True)
    def __unicode__(self):
        return self.domain_name
    def link_to(self, gibo_site):
        self.domain = gibo_site
        self.domain_name = gibo_site.domain

class PEMUserDetailsForm(forms.ModelForm):
    PEM_password = forms.CharField(widget=forms.PasswordInput)
    PEM_password_confirm = forms.CharField(widget=forms.PasswordInput)
    class Meta:
        model = PEMUserDetails
        exclude = ('domain', 'domain_name', 'FTP_login', 'FTP_password', 'FTP_host_name')


    def clean_PEM_login_id(self):
        login = self.cleaned_data['PEM_login_id']
        try:
            g = PEMUserDetails.objects.get(PEM_login_id=login)
            raise forms.ValidationError("This Login ID is already taken, please choose another.")
        except PEMUserDetails.DoesNotExist:
                p = PBA()
                pem_account = p.BM.UserValidate_API(login)
                if pem_account['AccountID'] == 0:
                    pass
                else:
                    raise forms.ValidationError("This Login ID is already taken, please choose another.")
                validation = p.BM.GetLoginSettings_API()
                m = re.match(validation['ManualLoginMask'], login)
                if m == None:
                    raise forms.ValidationError(validation['LoginAlert'])
                valid_login = (login == m.group(0))
                if len(login) > validation['LoginMinLength'] and len(login) < validation['LoginMaxLength'] and valid_login:
                    pass
                else:
                    raise forms.ValidationError(validation['LoginAlert'])
        return login

    def clean_PEM_password(self):
        p = PBA()
        login = self.cleaned_data['PEM_login_id']
        password = self.cleaned_data['PEM_password']
        validation = p.BM.GetLoginSettings_API()
        if len(password) > validation['PwdMinLength']:
            pass
        else:
            raise forms.ValidationError("Password must be more than %s characters long" % validation['PwdMinLength'])
        passwd_status = p.BM.UserForVendorValidate_API(login, password)
        if passwd_status['passwordStrength'] == '':
            pass
        else:
            raise forms.ValidationError(passwd_status['passwordStrength']) 
        return password

    def clean_PEM_password_confirm(self):
        p = self.cleaned_data['PEM_password']
        c = self.cleaned_data['PEM_password_confirm']
        if c == p:
            pass
        else:
            raise forms.ValidationError("The passwords you submitted do not match")
        return c

我通过使用常规表单并将其与模型类匹配来解决这个问题。它摆脱了这个问题。这是django 1.1中模型形式的限制吗?

python shell显示了这个

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from gibo.deployment.models import PEMUserDetailsForm
>>> from django.http import QueryDict
>>> post = QueryDict("PEM_login_id=beefsupreme&PEM_password=beef1234&PEM_password_confirm=beef123")
>>> f = PEMUserDetailsForm(post)
>>> f.is_valid()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 120, in is_valid
    return self.is_bound and not bool(self.errors)
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 111, in _get_errors
    self.full_clean()
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 243, in full_clean
    value = getattr(self, 'clean_%s' % name)()
  File "/home/niall/public_html/projects/GIBO/dev/projects/signup/gibo/../gibo/deployment/models.py", line 776, in clean_PEM_password
    login = self.cleaned_data['PEM_login_id']
KeyError: 'PEM_login_id'
>>> post = QueryDict("PEM_login_id=beefsupremexxc&PEM_password=beef1234&PEM_password_confirm=beef123")
>>> f = PEMUserDetailsForm(post)
>>> f.is_valid()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 120, in is_valid
    return self.is_bound and not bool(self.errors)
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 111, in _get_errors
    self.full_clean()
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 243, in full_clean
    value = getattr(self, 'clean_%s' % name)()
  File "/home/niall/public_html/projects/GIBO/dev/projects/signup/gibo/../gibo/deployment/models.py", line 791, in clean_PEM_password_confirm
    p = self.cleaned_data['PEM_password']
KeyError: 'PEM_password'
>>> f.errors
{'PEM_password': [u'Password is based on personal information.']}
>>> 

但它的工作原理

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from gibo.deployment.models import PEMUserDetailsForm
>>> from django.http import QueryDict
>>> post = QueryDict("PEM_login_id=beefsupreme&PEM_password=beef1234&PEM_password_confirm=beef123")
>>> f = PEMUserDetailsForm(post)
>>> f.errors
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 111, in _get_errors
    self.full_clean()
  File "/usr/lib/pymodules/python2.6/django/forms/forms.py", line 243, in full_clean
    value = getattr(self, 'clean_%s' % name)()
  File "/home/niall/public_html/projects/GIBO/dev/projects/signup/gibo/../gibo/deployment/models.py", line 777, in clean_PEM_password
    login = self.cleaned_data['PEM_login_id']
KeyError: 'PEM_login_id'
>>> f.errors
{'PEM_login_id': [u'This Login ID is already taken, please choose another.']}
>>> f.is_valid()
False
>>> 

2 个答案:

答案 0 :(得分:3)

特定于字段的清理方法 - clean_PEM_password()等 - 应该只从self.cleaned_data访问该特定字段。其他字段无法保证尚未设置。如果需要针对多个字段进行验证,则应使用clean()方法,因为已经运行了所有特定于字段的验证方法。

Cleaning and validating fields that depend on each other

答案 1 :(得分:0)

在执行字段验证功能时,您无法访问“cleaning_data”,因为只有在所有字段都通过验证后才能访问cleaning_data。

因此,您要么找到一种没有“cleaning_data”的工作方式,要么定义一个clean()方法,您可以在其中访问“cleaning_data”,然后编写自定义验证逻辑并在需要时抛出ValidationErrors。

我倾向于在我自己的项目中使用选项b,除非我真的创建了一种新类型的表单域,其中需要进行自定义验证 - 尤其是在检查数据库中是否存在数据时。