开发者

django forms.ModelForm validation problem

开发者 https://www.devze.com 2023-02-23 06:48 出处:网络
I have a model with some fields. I have a model form that represents a portion of the above model. I have to do some custom validation.Some fields depend on others.Password and password confirm field

I have a model with some fields.

I have a model form that represents a portion of the above model. I have to do some custom validation. Some fields depend on others. Password and password confirm fields must be the same for example. Its tied to a back end system.

I must check the login name ( ensure its not in the back end system and its not in the database for this project ). I must validate the length and so on.

I must then validate the password against the constraints set in the back end. I need to use an API for this. I must pass the login name in with the password to use this command ( its silly but I cannot change it. )

If the login name raised a validation error in its method then the password validation methid cannot use sel.cleaned_data['login']

here is the code.

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

I got around this by using a regular form and matched it to the model class. Its sort of running away from the problem. Is this a limitation of modelforms in django 1.1

python shell shows this

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.']}
>>> 

but it works this way

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


Field-specific clean methods -- clean_PEM_password(), etc -- should only access that specific field from self.cleaned_data. Other fields aren't guaranteed to be set yet. If you need to validate against multiple fields, you should use the clean() method, as all of the field-specific validation methods will already have been run.

Cleaning and validating fields that depend on each other


You cannot access "cleaned_data" when doing in field validation functions as you only get access to cleaned_data once all fields have passed validation.

So you either find a way to work without "cleaned_data" or you define a clean() method where you can access "cleaned_data" and then write your custom validation logic and throw ValidationErrors when needed.

I tend to go with option b in my own projects unless I really create a new type of formfield where custom validation is necessary - especially when checking for existence of data in my database.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号