Django REST Framework验证slug字段

时间:2015-02-09 06:54:26

标签: python django django-rest-framework

我已经定义了一个这样的序列化器:

class ActivitySerializer(serializers.ModelSerializer):
      activity_project = serializers.SlugRelatedField(queryset=Project.objects.all(), slug_field='project_name')

activity_tags = serializers.SlugRelatedField(queryset=Tag.objects.all(), slug_field='tag_name', many=True)
class Meta:
    model = Activity
    fields = ('activity_name', 'activity_description', 'activity_status', 'activity_completion_percent', 'activity_due_date', 'activity_project', 'activity_tags',)

现在,如果我插入一个在数据库中不存在的activity_tag,我会收到验证错误“

{
    "activity_tags": [
        "Object with tag_name=test does not exist."
    ]
}

我想创建一个验证方法,如果它不存在,则在数据库中添加标记。 我尝试过使用

def validate(self, attrs): 
    ....

方法,但显然对于一个slug字段,有一个方法在此之前被调用。

有人能指出我应该使用的正确方法吗?是否可以在相应的视图中调用此方法?

2 个答案:

答案 0 :(得分:1)

我认为您需要创建一个嵌套的序列化程序才能实现此功能。这是完全未经测试的,并且不在我的头顶,但也许是这样的:

class ActivityTagFieldSerializer(serializer.ModelSerializer):
    tag_name = serializers.SlugField()
    class Meta:
        model = Tag
        fields = ('tag_name')

class ActivitySerializer(serializer.ModelSerializer):
    activity_tags = ActivityTagFieldSerializer(many=True)
    class Meta:
        model = Activity
        fields = ('activity_tags', 'activity_project', ...)

    def create(self, validated_data):
        tags = validated_data.pop('activity_tags')
        activity = Activity.objects.create(**validated_data)
        for tag in tags:
            try:
                tag_to_add = Tag.objects.get(**tag)
            except:
                tag_to_add = Tag.objects.create(**tag)
            activity.activity_tags.add(tag_to_add)
        return activity

查看writable nested serializers

的API指南

答案 1 :(得分:0)

我通过子类化SlugRelatedField并重写“ to_internal_value”方法来做到这一点。在原始实现中,此方法尝试从查询集中获取对象,如果不存在对象,则验证失败。因此,不是调用“ get”方法,而是调用“ get_or_create”:

class CustomSlugRelatedField(serializers.SlugRelatedField):
    def to_internal_value(self, data):
        try:
            obj, created = self.get_queryset().get_or_create(**{self.slug_field: data})
            return obj
        except (TypeError, ValueError):
            self.fail('invalid')