'Trying To Retrieve Name Instead of Primary Key, But Django Rest Framework complains of Value Error. If I try to fix it, I got other errors too

My Models:

  def upload_to(instance, filename):
      return 'images/{filename}'.format(filename=filename)

  class StreamPlatform(models.Model):
      name = models.CharField(max_length=200)
      about = models.TextField(max_length=2000)
      website = models.URLField(max_length=2500)
  
      def __str__(self):
          return self.name

  class WatchList(models.Model):
      title = models.CharField(max_length=250)
      image = models.ImageField(_('Image'), upload_to=upload_to, default='images/default.jpg')
      storyline = models.TextField(max_length=2000)
      platform = models.ForeignKey(StreamPlatform, on_delete=models.CASCADE, related_name='watchlist')
      active = models.BooleanField(default=True)
      avg_rating = models.FloatField(default=0)
      number_rating = models.IntegerField(default=0)
      created = models.DateTimeField(auto_now_add=True)
  
      def __str__(self):
          return self.title

My Serializers:

class WatchListSerializer(serializers.ModelSerializer):
    platform = serializers.CharField(source='platform.name')
    class Meta:
        model = WatchList
        fields = '__all__'
        extra_kwargs = {'avg_rating': {'read_only': True}, 'number_rating': {'read_only': True}}
    def create(self, validated_data):
        return WatchList.objects.create(**validated_data)

class StreamPlatformSerializer(serializers.ModelSerializer):
    watchlist = WatchListSerializer(many=True, read_only=True)
    class Meta:
        model = StreamPlatform
        fields = '__all__'

My View:

class WatchListAV(generics.ListCreateAPIView):
    permission_classes = [AdminOrReadOnly]
    parser_classes = [MultiPartParser, FormParser]
    queryset = WatchList.objects.all()
    serializer_class = WatchListSerializer
    pagination_class = WatchListLimitOffsetPagination
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['title', 'platform__name']
    ordering_fields = ['avg_rating']

The issue I got is that Django Rest Framework complains in PostMan that:

ValueError at /watch/list/ Cannot assign "{'name': '8'}": "WatchList.platform" must be a "StreamPlatform" instance.

When I try to fix it like this in the WatchListSerializer:

platform = serializers.PrimaryKeyRelatedField(queryset = StreamPlatform.objects.all(), source='platform.name',)

I got a new error instead:

ValueError at /watch/list/ Cannot assign "{'name': <StreamPlatform: Blah>}": "WatchList.platform" must be a "StreamPlatform" instance.

When I commented out the error-prone code bits, I got the correct Response, just not the Response I'm hoping for.

{
    "id": 26,
    "title": "Awesome Show Blah Blah",
    "image": "http://127.0.0.1:8000/media/images/default.jpg",
    "storyline": "Any blah...",
    "active": true,
    "avg_rating": 0.0,
    "number_rating": 0,
    "created": "2022-05-12T17:04:04.151048Z",
    "platform": 8
}

I'm hoping for the "platform": 8 to be shown in name like "platform": Blah. So how do you fix this?



Solution 1:[1]

You can use the SlugRelatedField.

class WatchListSerializer(serializers.ModelSerializer):
    platform = serializers.SlugRelatedField(many=True, queryset=StreamPlatform.objects.all(), slug_field='name')
    class Meta:
        model = WatchList
        fields = ['platform', 'all_other_fields']
        extra_kwargs = {
            'avg_rating': {'read_only': True}, 
            'number_rating': {'read_only': True}
        }
    def create(self, validated_data):
        return WatchList.objects.create(**validated_data)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1