Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
“clean”和“clean_fieldname”方法能否在Django ModelForm中一起使用?_Django_Validation_Django Forms_Modelform - Fatal编程技术网

“clean”和“clean_fieldname”方法能否在Django ModelForm中一起使用?

“clean”和“clean_fieldname”方法能否在Django ModelForm中一起使用?,django,validation,django-forms,modelform,Django,Validation,Django Forms,Modelform,我正在尝试在网站上通过电子邮件和电话进行注册。用户可以通过电话或电子邮件注册,也可以同时通过电话或电子邮件注册。如果用户同时将电话和电子邮件字段保留为空,则会引发一个ValidationError,“您不能同时将电话和电子邮件字段保留为空。您必须至少填写其中一个字段。” 对于用户名、电子邮件、电话、密码,我们有单独的clean方法。我不想在save()上实现上述验证。我也不想在用户模型中定义clean方法。 我已经为这份表格写了笔试,他们通过了。但是如果我同时使用clean和clean_fiel

我正在尝试在网站上通过电子邮件和电话进行注册。用户可以通过电话或电子邮件注册,也可以同时通过电话或电子邮件注册。如果用户同时将电话和电子邮件字段保留为空,则会引发一个
ValidationError
,“您不能同时将电话和电子邮件字段保留为空。您必须至少填写其中一个字段。”

对于
用户名、电子邮件、电话、密码
,我们有单独的
clean
方法。我不想在
save()
上实现上述验证。我也不想在用户模型中定义
clean
方法。 我已经为这份表格写了笔试,他们通过了。但是如果我同时使用
clean
clean_fieldname
,可能会出现什么错误呢?使用视图时是否会出现问题

我有3个问题:

  • 我是否可以同时使用
    clean_fieldname
    clean
    方法 表格?
  • 我还可以通过什么方式确保用户至少向 电话还是电子邮件
  • clean()
    validate()
    如何工作?我已经阅读了django文档,但我不完全理解它
  • 下面是我实现的代码

    class RegisterForm(SanitizeFieldsForm, forms.ModelForm):
        email = forms.EmailField(required=False)
    
        message = _("Phone must have format: +9999999999. Upto 15 digits allowed."
                    " Do not include hyphen or blank spaces in between, at the"
                    " beginning or at the end.")
        phone = forms.RegexField(regex=r'^\+(?:[0-9]?){6,14}[0-9]$',
                                 error_messages={'invalid': message},
                                 required=False)
        password = forms.CharField(widget=forms.PasswordInput())
        MIN_LENGTH = 10
    
        class Meta:
            model = User
            fields = ['username', 'email', 'phone', 'password',
                      'full_name']
    
        class Media:
            js = ('js/sanitize.js', )
    
        def clean(self):
            super(RegisterForm, self).clean()
    
            email = self.data.get('email')
            phone = self.data.get('phone')
    
            if (not phone) and (not email):
                raise forms.ValidationError(
                    _("You cannot leave both phone and email empty."
                      " Signup with either phone or email or both."))
    
        def clean_username(self):
            username = self.data.get('username')
            check_username_case_insensitive(username)
            if username.lower() in settings.CADASTA_INVALID_ENTITY_NAMES:
                raise forms.ValidationError(
                    _("Username cannot be “add” or “new”."))
            return username
    
        def clean_password(self):
            password = self.data.get('password')
            validate_password(password)
            errors = []
    
            email = self.data.get('email')
            if email:
                email = email.split('@')
                if email[0].casefold() in password.casefold():
                    errors.append(_("Passwords cannot contain your email."))
    
            username = self.data.get('username')
            if len(username) and username.casefold() in password.casefold():
                errors.append(
                    _("The password is too similar to the username."))
    
            phone = self.data.get('phone')
            if phone:
                if phone_validator(phone):
                    phone = str(parse_phone(phone).national_number)
                    if phone in password:
                        errors.append(_("Passwords cannot contain your phone."))
    
            if errors:
                raise forms.ValidationError(errors)
    
            return password
    
        def clean_email(self):
            email = self.data.get('email')
            if email:
                if User.objects.filter(email=email).exists():
                    raise forms.ValidationError(
                        _("Another user with this email already exists"))
            return email
    
        def clean_phone(self):
            phone = self.data.get('phone')
            if phone:
                if User.objects.filter(phone=phone).exists():
                    raise forms.ValidationError(
                        _("Another user with this phone already exists"))
            return phone
    
        def save(self, *args, **kwargs):
            user = super().save(*args, **kwargs)
            user.set_password(self.cleaned_data['password'])
            user.save()
            return user
    

    你可以从阅读Django代码中得到很多东西;这是一个评论良好的代码库!相关章节见。当表单被清理/验证时,它将调用
    full\u clean
    。这将首先调用
    \u clean\u fields
    ,它调用字段
    clean
    ,并在要调用的表单上查找
    clean{fieldname}
    方法。然后,调用表单
    clean

    def full_clean(self):
        """
        Clean all of self.data and populate self._errors and self.cleaned_data.
        """
        self._errors = ErrorDict()
        if not self.is_bound:  # Stop further processing.
            return
        self.cleaned_data = {}
        # If the form is permitted to be empty, and none of the form data has
        # changed from the initial data, short circuit any validation.
        if self.empty_permitted and not self.has_changed():
            return
    
        self._clean_fields()
        self._clean_form()
        self._post_clean()
    
    def _clean_fields(self):
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value
            except ValidationError as e:
                self.add_error(name, e)
    
    def _clean_form(self):
        try:
            cleaned_data = self.clean()
        except ValidationError as e:
            self.add_error(None, e)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data
    
    事实上,这本书也明确地解释了这个顺序。