Странное поведение в Django формах - PullRequest
4 голосов
/ 05 марта 2020

Я работал с Django Формами, я делал пользовательскую проверку для поля, но столкнулся со странной проблемой.

forms.py

class RegistrationForm(forms.Form):
    username = forms.CharField(max_length=50)
    email = forms.EmailField(required=False)
    password = forms.CharField(max_length=50)
    password1 = forms.CharField(max_length=50)        

    def clean_password(self):
        password = self.cleaned_data['password']
        print(self.cleaned_data) # all fields are present except password1 in cleaned Data
        re_password = self.cleaned_data['password1'] #Gives Key Error here
        # Do something

Здесь, когда я пытаюсь выполнить некоторую проверку поля пароля в функции clean_password, выдает ошибку ключа для поля password1, я не понимаю, почему это происходит. Я пытался много искать, но не смог найти ничего подходящего, о причинах этой ошибки. Но потом я попытался внести некоторые изменения в код, и это сработало, но я не знаю, почему это сработало.

updated_forms.py

class RegistrationForm(forms.Form):
    username = forms.CharField(max_length=50)
    email = forms.EmailField(required=False)
    password1 = forms.CharField(max_length=50)    #swapped position    
    password = forms.CharField(max_length=50)

    def clean_password(self):
        password = self.cleaned_data['password']
        print(self.cleaned_data) # all fields are present in cleaned Data
        re_password = self.cleaned_data['password1'] #Doesn't Give Key Error here
        # Do something

Я сделал следующие изменения: я просто поменял местами положение строки password1 и password, то есть я только что изменил порядок password и password1. Я изменил заказ password1 в строке password, password в позиции, где было password1. И это решило ошибку, я не понимаю, это поведение из того, что я знаю, что порядок полей не должен ничего влиять Может кто-нибудь объяснить, что здесь происходит? Спасибо :)

Ответы [ 3 ]

2 голосов
/ 09 марта 2020

Это не странное поведение. Django формы работают таким образом. Пожалуйста, посмотрите на исходный код здесь , чтобы понять, как работает очистка полей для django форм. Вот урезанная версия метода _clean_fields.

def _clean_fields(self):
    for name, field in self.fields.items():
        # skipped
        try:
            # skipped
            value = field.clean(value)
            self.cleaned_data[name] = value
            if hasattr(self, 'clean_%s' % name):
                # skipped
                value = getattr(self, 'clean_%s' % name)()
                self.cleaned_data[name] = value
        except ValidationError as e:
            self.add_error(name, e)

То, что он делает, это l oop над полями формы и для каждого поля помещает свое очищенное значение в cleaned_data dict. Если определен метод очистки поля (clean_<FIELD_NAME>), он вызывает этот метод для очищенных данных для этого поля и помещает его в cleaned_data dict.

В вашем первом случае password1 следует после password. Поскольку поля очищаются по порядку, password1 еще не очищается, когда вы пытаетесь получить к нему доступ в методе clean_password. Это означает, что его очищенное значение еще не присутствует в cleaned_data dict.

Во втором случае вы меняете положение password и password1. Теперь очистка была выполнена для password1, и вы можете получить доступ к ее значению.

Практическое правило заключается в том, что для clean_<FIELD_NAME> метода, вы можете получить доступ только к очищенным значениям тех полей, которые были объявлены ранее. это поле c .

Решение

Вы должны сделать это, как django в UserCreationForm . Они проверяют совпадение пароля во втором поле, т.е. пароль1 должен совпадать с паролем, а не наоборот (что по сути одинаково). Фрагмент с модификацией от здесь .

def clean_password1(self):
    password = self.cleaned_data.get("password")
    password1 = self.cleaned_data.get("password1")
    if password and password1 and password != password1:
        raise forms.ValidationError('Passwords do not match')
    return password1
1 голос
/ 05 марта 2020

Вы используете python. python является языком типов сценариев и использует интерпретатор, поэтому код будет оценивать строку за строкой

, в вашем случае вы создаете def clean_password(self), поэтому этот метод вызывается после получения пароля из формы в ленивом вычислении. если вы переименовываете свой метод без замены password и password1 переименовываете свой метод с помощью def clean_password1(self), он прекрасно работает

forms.py

class RegistrationForm(forms.Form):
    username = forms.CharField(max_length=50)
    email = forms.EmailField(required=False)
    password = forms.CharField(max_length=50)
    password1 = forms.CharField(max_length=50)        

    def clean_password1(self):
        password = self.cleaned_data['password']
        print(self.cleaned_data) # all fields are present
        re_password = self.cleaned_data['password1']

если вы удовлетворены моим ответом, дайте мне знать

0 голосов
/ 08 марта 2020

Я думаю, что лучше использовать отдельные чистые методы для полей password и password1

def clean_password(self):
    password = self.cleaned_data['password']
    # Do something

def clean_password1(self):
    password1 = self.cleaned_data['password1']
    # Do something

Или проверить оба в clean () method

def clean(self):
    cleaned_data = super().clean()
    password = cleaned_data['password']
    re_password = cleaned_data['password1']
    # Do something
...