Home > Enterprise >  Django - Serializer not setting ManyToManyField
Django - Serializer not setting ManyToManyField

Time:10-19

For some reason the following code isn't setting the hash_tags attribute under Post. The way I checked was I put a breakpoint at the return Response line in view.py and I checked the newly created Post object and the hash_tags attribute just returned an empty list. Also when I read the serializer.data, hash_tags is an empty list as well. Even though the HashTag table clearly created the hash tag found in the body. What's going on?

model.py

class Post(AbstractBaseModel):
    creator = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="post_creator")
    join_goal = models.ForeignKey(JoinGoal, on_delete=models.CASCADE)
    body = models.CharField(max_length=511, validators=[MinLengthValidator(5)])
    hash_tags = models.ManyToManyField(HashTag)
    type = models.CharField(
        choices=PostType.choices,
        max_length=50,
    )

class HashTag(models.Model):
    hash_tag = models.CharField(max_length=140, primary_key=True, validators=[
        MinLengthValidator(1)])

Serializer.py

class HashTagSerializer(serializers.ModelSerializer):
    class Meta:
        model = HashTag
        fields = ['hash_tag']

class PostSerializer(serializers.ModelSerializer):
    hash_tags = HashTagSerializer(many=True, read_only=True)

    class Meta:
        model = Post
        fields = ('creator', 'join_goal', 'body', 'uuid', 'created', 'type', 'updated_at', 'hash_tags')

view.py

@api_view(['POST'])
def post_create_update_post(request):
    user_uuid = str(request.user.uuid)

    request.data['creator'] = user_uuid
    request.data['type'] = PostType.UPDATE
    post_text = request.data['body']
    hash_tags_list = extract_hashtags(post_text)
    hash_tags = [HashTag.objects.get_or_create(hash_tag=ht)[0].hash_tag for ht in hash_tags_list]
    request.data['hash_tags'] = hash_tags

    try:
        with transaction.atomic():
            serializer = PostSerializer(data=request.data)
            if serializer.is_valid(raise_exception=True):
                post_obj = serializer.save()
    except Exception as e:
        return Response(dict(error=str(e),
                             user_message=error_message_generic),
                        status=status.HTTP_400_BAD_REQUEST)

    return Response(serializer.data, status=status.HTTP_201_CREATED)

I also tried not setting read_only=True and get this error

this leads to ValidationError({'hash_tags': [ErrorDetail(string='This field is required.', code='required')]}) with request.data['hash_tags']=['Test']

CodePudding user response:

You set read_only=True This is why hash_tags value not saving on the database.

hash_tags = HashTagSerializer(many=True, read_only=True)

Declare it without read_only like this:

hash_tags = HashTagSerializer(many=True)

CodePudding user response:

I believe that you have to override the create and update method for the nested serializer in serializer.py:

class HashTagSerializer(serializers.ModelSerializer):
   class Meta:
      model = HashTag
      fields = ['hash_tag']

class PostSerializer(serializers.ModelSerializer):
    hash_tags = HashTagSerializer(many=True, read_only=True)

   class Meta:
      model = Post
      fields = ('creator', 'join_goal', 'body', 'uuid', 'created', 'type', 'updated_at', 'hash_tags')

      def create(self, validated_data):
         hash_tags_data = validated_data.pop('hash_tags')
         post = Post.objects.create(**validated_data)
         for data in hash_tags_data:
            hash_tag = HashTag.objects.get_or_create(**data)
            post.hash_tags.add(hash_tag)
         post.save()
         return post
  • Related