我有用户表,其中必须对员工用户设置唯一的电子邮件约束,并对非员工用户设置唯一的电话限制。现在我想在DRF API和Django admin中维护这个约束,如何在没有代码重复的情况下实现这一点。
正如我从DRF 3.0开始看到的,所有验证都是针对序列化器显式执行的(如果我已经覆盖了unique_validation或clean方法来执行条件验证,我必须单独为序列化器编写这个自定义验证)所以如何编写一个自定义验证适用于DRF API和Django管理员而无需重复代码?
答案 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