[Fixed]-Django Rest Framework – Create foreign key object on POST

21👍

Overriding the create() method of the serializer as

class ArticleSerializer(serializers.ModelSerializer):
    tags = serializers.CharField()

    class Meta:
        model = Article
        fields = '__all__'

    def create(self, validated_data):
        tag = validated_data.pop('tags')
        tag_instance, created = Tag.objects.get_or_create(name=tag)
        article_instance = Article.objects.create(**validated_data, tags=tag_instance)
        return article_instance
👤JPG

2👍

Okay, thanks to @JPG for their help. This is what I’ve ended up with. It allows users to add space delimited tags into a CharField on the /api/blog/article endpoint. When a POST request is performed, the tags are split on spaces, get_or_create()d (for this to work I needed to make Tag.name the primary key), and then added to the Article with article.tags.set(tag_list). As @JPG and @Martins suggested, a ManyToManyField() was the best way to do this.

Here is my full code:

serializers.py:

class ArticleSerializer(serializers.ModelSerializer):

    class TagsField(serializers.CharField):

        def to_representation(self, tags):
            tags = tags.all()
            return "".join([(tag.name + " ") for tag in tags]).rstrip(' ')


    tags = TagsField()

    class Meta:
        model = Article
        fields = '__all__'

    def create(self, validated_data):

        tags = validated_data.pop('tags') # Removes the 'tags' entry
        tag_list = []
        for tag in tags.split(' '):
            tag_instance, created = Tag.objects.get_or_create(name=tag)
            tag_list += [tag_instance]

        article = Article.objects.create(**validated_data)
        print(tag_list)
        article.tags.set(tag_list)
        article.save()
        return article


class TagSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tag
        fields = '__all__'

Note that I had to create a custom TagField() and override to_representation(). This is because if I used a regular serializer.CharField() tags were displayed as: “Blog.tag.None” instead of the tag values, like this:

Blog.tag.None

models.py:

class Tag(models.Model):

    name = models.CharField(max_length=32, primary_key=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ('name',)

class Article(models.Model):

    title = models.CharField(max_length=256)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField(Tag)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ('date', 'id')
👤Sam

Leave a comment