djangodjango-rest-frameworkdjango-serializerdjango-taggit

Using Django-Taggit in Django Rest Framework 3.13.1 with Django 4.0.2 with Error "Invalid json list" in Serializing Tags Model Attribute


Older solutions uses django-taggit-serializer which is now been deprecated and doesn't work with the version I have.

I have already done what the documentation says regarding the integration with DRF.

However, I am getting this error:

b'{"tags":["Invalid json list. A tag list submitted in string form must be valid json."]}'

image error in drf browsable api

Here is my code

viewset.py

class AnnouncementViewSet(viewsets.ModelViewSet):
    """Announcement ViewSet."""

    queryset = Announcement.objects.all()
    serializer_class = AnnouncementSerializer
    lookup_field = "slug"
    permission_classes = [IsAdminUser, IsAuthorOrReadOnly]

    def get_permissions(self):
        """Return permissions."""
        if self.action in ["create", "update", "partial_update", "destroy"]:
            self.permission_classes = [IsAdminUser]
        else:
            self.permission_classes = [IsAuthorOrReadOnly]
        return super().get_permissions()

models.py

class Announcement(models.Model):
    """Announcement model."""

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    title = models.CharField(_("title"), max_length=255, unique=True)
    content = models.TextField(_("content"))
    is_featured = models.BooleanField(default=False)
    thumbnail = models.ImageField(
        upload_to="announcement/thumbnail", default="announcement/thumbnail/default.jpg"
    )
    tags = TaggableManager(_("tags"))
    slug = models.SlugField(_("Slug"), max_length=255, unique=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super().save(*args, **kwargs)

serializers.py

class AnnouncementSerializer(TaggitSerializer, serializers.ModelSerializer):
    tags = TagListSerializerField()
        
    class Meta:
        model = Announcement
        exclude = ["slug"]

        extra_kwargs = {
            "url": {"view_name": "api:announcement-detail", "lookup_field": "slug"}
        }

What I have tried so far:

tags = "my-tag"

tags = ["tag1", "tag2"]

I even wrote a test:

tests.py

def test_announcement_create_url(
    self, api_client: Client, admin_user
):
    api_client.force_login(admin_user)
    response = api_client.post(
        reverse("api:announcement-list"),
        {
            "title": "This is a new announcement",
            "content": "This is the content of the new announcement",
            "is_featured": "True",
            "tags": ["tag1", "tag2"],
        },
    )
    print(response.content)
    assert response.status_code == status.HTTP_201_CREATED

But it produces the same error.

I also found this GitHub issue but again, django-taggit-serializer is deprecated and is not being maintained anymore.


Solution

  • Found my own answer. The cause of the error is my tags Model Attribute.

    If your Model Attribute is named tags then you need to do this in order to submit or tests your API query:

    Browsable API

    {
        "tags": ["tag1", "tag2"]
    }
    

    Python Code

    {
        "tags": '["tag1", "tag2"]'
    }
    

    Some fields are omitted for brevity. Make sure to include the required fields needed by your serializer.