Django自定义序列化器验证unique字段

kmynzznz  于 2023-08-08  发布在  Go
关注(0)|答案(2)|浏览(128)

我正在尝试使用DRF编写用户注册的自定义邀请系统。我需要单独的路径,只检查代码是有效的。如果这个代码存在于数据库中,我会使用序列化器返回is_valid = False,因为代码字段在模型中被定义为Unique。我需要相反的行为。
机型

class InviteCode(models.Model):
    code = models.CharField(max_length=32, null=False, unique=True)
    referal = models.ForeignKey(to=User, null=True, blank=True, on_delete=models.CASCADE, related_name='%(class)s_referal')
    is_teacher = models.BooleanField(default=False)
    used_by = models.ForeignKey(to=User, null=True, blank=True, on_delete=models.CASCADE, related_name='%(class)s_used_by')

字符串
串行化器

class InviteCodeSerializer(serializers.ModelSerializer):
    class Meta:
        model = InviteCode
        fields = "__all__"


我尝试将validate_code()方法添加到序列化器中以进行自定义验证

def validate_code(self, value):
        code = InviteCode.objects.filter(code = value).first()
        if code is None:
            raise serializers.ValidationError("Invite code doesn't exist")
        #Other validation checks
        return code


但是它是在唯一检查之后调用的,所以在数据库中存在代码的情况下,方法不会被调用,我仍然会得到

{'code': [ErrorDetail(string='invite code with this code already exists.', code='unique')]}


在序列化程序上调用is_valid后

tvz2xvvm

tvz2xvvm1#

为了实现您想要的行为,即使代码存在于数据库中,序列化程序的is_valid方法也返回True,您可以在序列化程序中使用validate_unique方法。validate_unique方法是在调用所有单独的字段级验证方法(包括validate_code)之后调用的。
下面是如何修改序列化程序来处理这个问题:

from rest_framework import serializers

class InviteCodeSerializer(serializers.ModelSerializer):
    class Meta:
        model = InviteCode
        fields = "__all__"

    def validate_code(self, value):
        # Your custom validation checks
        # ...

        return value

    def validate_unique(self, attrs):
        # Check for the uniqueness of code explicitly
        if "code" in attrs:
            code = attrs["code"]
            existing_code = InviteCode.objects.filter(code=code).exists()
            if existing_code:
                # You can raise a validation error here if you want to
                # but in your case, you want to allow duplicate codes
                pass

        # Call the parent's validate_unique method to handle other uniqueness checks
        return super().validate_unique(attrs)

字符串
通过覆盖validate_unique方法,可以对code字段执行自定义唯一性检查,并允许重复代码而不会引发验证错误。
现在,这将允许您创建具有重复代码的序列化程序,而不会在序列化程序上调用is_valid时引发唯一性错误。但是,请注意,您需要自己处理唯一性约束,因为Django在这种情况下不会自动处理它。

yruzcnhs

yruzcnhs2#

还没有找到使用这种方法的解决方案。相反,我修改模型,以删除代码字段上的唯一参数

class InviteCode(models.Model):
code = models.CharField(max_length=32, null=False)
referal = models.ForeignKey(to=User, null=True, blank=True, on_delete=models.CASCADE, related_name='%(class)s_referal')
is_teacher = models.BooleanField(default=False)
used_by = models.ForeignKey(to=User, null=True, blank=True, on_delete=models.CASCADE, related_name='%(class)s_used_by')

字符串
并在序列化器validate_code()方法中提供了检查数据库中是否存在代码的功能

class InviteCodeSerializer(serializers.ModelSerializer):
class Meta:
    model = InviteCode
    fields = "__all__"
def validate_code(self, value):
    code = InviteCode.objects.filter(code = value).first()
    if code is None:
        raise serializers.ValidationError("Invite code doesn't exist")
    #Other validation checks
    return code


此外,还增加了管理面板的重复检查,以防止在通过管理面板添加时出现代码重复admin.py

class InviteCodeAdminForm(forms.ModelForm):
def clean_code(self):
    #check fro duplication here
    return self.cleaned_data["code"]
class AdminInviteCode(admin.ModelAdmin):
form = InviteCodeAdminForm
admin.site.register(InviteCode, AdminInviteCode)

相关问题