Reputation: 91
I have defined a serializer like this:
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',)
Now if I insert an activity_tag that does not exist in the database, I get a validation error"
{
"activity_tags": [
"Object with tag_name=test does not exist."
]
}
I would like to create a validation method that adds the tag in the database if it does not exist. I have tried using the
def validate(self, attrs):
....
method, but apparently for a slug field there is a method that is called before this one.
Can someone point me to the right method I should use? Would this method be called in the corresponding view?
Upvotes: 3
Views: 2371
Reputation: 1410
I managed to do this by subclassing SlugRelatedField and overriding "to_internal_value" method. In the original implementation this method tries to get an object from the queryset, and if an object doesn't exist it fails the validation. So instead of calling "get" method, I'm calling "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')
Upvotes: 2
Reputation: 119
I think you would need to create a nested serializer for this to work. This is totally untested and off the top of my head, but maybe something like this:
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
Check the API guide for writable nested serializers
Upvotes: 1