DRF和Django管理员的常见自定义验证

时间:2017-01-09 06:23:34

标签: django django-rest-framework

我有用户表,其中必须对员工用户设置唯一的电子邮件约束,并对非员工用户设置唯一的电话限制。现在我想在DRF API和Django admin中维护这个约束,如何在没有代码重复的情况下实现这一点。

正如我从DRF 3.0开始看到的,所有验证都是针对序列化器显式执行的(如果我已经覆盖了unique_validation或clean方法来执行条件验证,我必须单独为序列化器编写这个自定义验证)所以如何编写一个自定义验证适用于DRF API和Django管理员而无需重复代码?

2 个答案:

答案 0 :(得分:1)

如果您的模型没有嵌套关系,这应该可行。


class ValidateModelMixin(object)
    def validate(self, attrs):
        attrs = super().validate(attrs)
        obj = self.Meta.model(**attrs)
        obj.clean()
        return attrs

class SomeModelSerializer(ValidateModelMixin, serializers.ModelSerializer):
    #...
    class Meta:
        model = SomeModel

但在我的情况下,我有嵌套模型,我需要覆盖序列化器中的create()和update()方法。我的解决方案只在一个地方保持验证:


def create(self, validated_data):
        # Remove nested and M2m relationships from validated_data
        firstmodel_set = validated_data.pop('firstmodel_set') if 'firstmodel_set' in validated_data else []
        .....
        # Get instance of project
        instance = Project(**validated_data)
        instance.clean()

        # If clean method doesn't raise any exception, create.
        project = instance.save()
        ......

如果你想要序列化验证消息..也许这样的东西会帮助你......

def validate_instance(instance):
    try:
        # Call model validation
        instance.clean()
    except ValidationError as e:
        raise serializers.ValidationError(e)

或者您可以使用信号并在pre_save()上进行验证。 看看https://docs.djangoproject.com/en/1.10/topics/signals/

答案 1 :(得分:0)

FOR API: 为UserRegistration创建一个序列化程序并实现validate方法,其中两个条件一用于唯一电子邮件,另一个用于电话号码。 类似于:

class UserCreateSerializer(ModelSerializer):
   class Meta:
        model = User
        fields = ['email','phone','...']
   def validate(self, data):
        """"user email phone validator """

        user_qs = User.objects.filter(email=data['email'], is_staff=True)
        if user_qs.exists():
            raise ValidationError({"email":"This user has already registered."})
        user_phone = User.objects.filter(phone=data['phone'], is_active=True, is_staff=False)
        if user_phone.exists():
            raise ValidationError({"phone":"Phone number already exists."})
        return data

FOR WEB: 如果您已经创建了注册表单,那么在表单中将clean方法实现为在上面的序列化器中验证。

class UserCreateForm(ModelForm):

    class Meta:
            model = User
            fields = ['email','phone','...']
    def clean(self):
            """"user email phone validator """

            user_qs = User.objects.filter(email=self.cleaned_data['email'], is_staff=True)
            if user_qs.exists():
                raise ValidationError({"email":"This user has already registered."})
            user_phone = User.objects.filter(phone=self.cleaned_data['phone'], is_active=True, is_staff=False)
            if user_phone.exists():
                raise ValidationError({"phone":"Phone number already exists."})
            return data