Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django-rest-framework many-to-many relations. Create if not exists

I try to send the following data to my django application:

{
    "hashtags": ["hashtag"], 
    "title": "title", 
    "message": "message"
}

and i get this response:

{
    "hashtags": [
        {
            "non_field_errors": [
                "Invalid data. Expected a dictionary, but got int."
            ]
        }
    ]
}

I have the following view defined in views.py

class PostList(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = IsAuthorizedOwnerOrReadOnly,

the models are defined like this:

class Post(models.Model):
    ambassador = models.OneToOneField("User")
    publish_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    hashtags = models.ManyToManyField("PostHashtags", related_query_name="posts")

    title = models.CharField(max_length=TEXT_SHORT, null=True, blank=True)
    message = models.CharField(max_length=TEXT_MIDDLE, null=True, blank=True)


class PostHashtags(models.Model):
    hashtag = models.CharField(max_length=TEXT_SHORT, null=False)

    def __unicode__(self):
        return self.hashtag

and i define the serializers like this:

class PostHashtagSerializer(serializers.ModelSerializer):

    class Meta:
        model = PostHashtags
        fields = ("hashtag",)


class PostSerializer(serializers.ModelSerializer):
    hashtags = PostHashtagSerializer(many=True)
    class Meta:
        model = Post
        fields = ("id", "hashtags", "title", "message",)
        read_only_fields = ("id", 'account_name',)

It seems like the hashtags are not created automatically using my current serialisation config. Is there a way to have my hashtags created if they do not yet exist, and if they do exist, have the Post use that same hashtag? In that case, how should my serialisers be defined?

EDIT 1: After GwynBleidD's suggestions I now get the following error:

The `.create()` method does not support writable nestedfields by default.
Write an explicit `.create()` method for serializer PostSerializer , or set `read_only=True` on nested serializer fields.

Does anyone have a suggestion for such a create method?

EDIT 2: solved it using the following serialisers

class PostHashtagSerializer(serializers.ModelSerializer):
    hashtag = serializers.CharField()
    class Meta:
        model = PostHashtags
        fields = ("hashtag",)


class PostSerializer(serializers.ModelSerializer):
    hashtags = PostHashtagSerializer(many=True,)

    class Meta:
        model = Post
        fields = ("ambassador", "hashtags", "title", "message",)

    def create(self, validated_data):
        hashtags_data = validated_data.pop('hashtags')

        post = Post.objects.create(**validated_data)
        for hashtag in hashtags_data:
            ht = PostHashtags.objects.create()
            ht.hashtag = hashtag.get("hashtag")
            ht.save()
            post.hashtags.add(ht)
        post.save()
        return post
like image 293
Eyeball Avatar asked Jan 23 '26 11:01

Eyeball


1 Answers

Hashtags are not string, but dict in that example. You have to submit:

{
    "hashtags": [{"hashtag": "hashtag"}], 
    "title": "title", 
    "message": "message"
}
like image 103
GwynBleidD Avatar answered Jan 26 '26 03:01

GwynBleidD