1

I am using django-rest-framework and django-taggit to add tags to my models.

My models are movie and book and both have only a title and tags

from django.db import models
from taggit.managers import TaggableManager


class Movie(models.Model):
    title = models.CharField(max_length=255, unique=True)
    tags = TaggableManager()

    def __str__(self):
        return self.title


class Book(models.Model):
    title = models.CharField(max_length=255, unique=True)
    tags = TaggableManager()

    def __str__(self):
        return self.title

I serialize the models and build the views

serializers.py

from rest_framework import serializers
from taggit_serializer.serializers import (TagListSerializerField,
                                           TaggitSerializer)


from .models import Movie, Book


class MovieSerializer(TaggitSerializer, serializers.ModelSerializer):

    tags = TagListSerializerField()
    
    class Meta:
        model = Movie
        fields = (
            'id',
            'title',
            'tags',
        )


class BookSerializer(TaggitSerializer, serializers.ModelSerializer):

    tags = TagListSerializerField()
    
    class Meta:
        model = Book
        fields = (
            'id',
            'title',
            'tags',
        )

views.py

from rest_framework import viewsets

from .models import Movie, Book
from .serializers import MovieSerializer, BookSerializer


class MovieViewSet(viewsets.ModelViewSet):
    serializer_class = MovieSerializer
    queryset = Movie.objects.all()


class BookViewSet(viewsets.ModelViewSet):
    serializer_class = BookSerializer
    queryset = Book.objects.all()

Here are also my ulrs.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),

    path('api/', include('apps.movie.urls')),
    path('api/', include('apps.book.urls')),
]
from django.urls import path, include
from rest_framework import urlpatterns

from rest_framework.routers import DefaultRouter

from .views import MovieViewSet, BookViewSet

router = DefaultRouter()
router.register('movie', MovieViewSet, basename='movie')
router.register('book', BookViewSet, basename='book')

urlpatterns = [
    path('', include(router.urls)),
]

As an example, I report two movies and two books in json format

## movies

{
    "id": 1,
    "title": "The Lord of the Rings: The Fellowship of the Ring",
    "tags": [
        "epic",
        "fantasy",
        "adventure"
    ]
}

{
    "id": 2,
    "title": "The Lord of the Rings: The Two Towers",
    "tags": [
        "epic",
        "fantasy",
        "adventure"
    ]
}


## books

{
    "id": 1,
    "title": "Harry Potter and the Philosopher's Stone",
    "tags": [
        "fantasy",
        "adventure"
    ]
}

{
    "id": 1,
    "title": "Crime and Punishment",
    "tags": [
        "psychological novel",
        "philosophical novel"
    ]
}

I can successfully reach these elements at

http://127.0.0.1:8000/api/movie/<id>/
http://127.0.0.1:8000/api/book/<id>/

What I want is a page for each tag to view both movies and books.

For example to the url

http://127.0.0.1:8000/api/tags/fantasy/

I want

{
    "id": 1,
    "title": "The Lord of the Rings: The Fellowship of the Ring",
    "tags": [
        "epic",
        "fantasy",
        "adventure"
    ]
}

{
    "id": 2,
    "title": "The Lord of the Rings: The Two Towers",
    "tags": [
        "epic",
        "fantasy",
        "adventure"
    ]
}

{
    "id": 1,
    "title": "Harry Potter and the Philosopher's Stone",
    "tags": [
        "fantasy",
        "adventure"
    ]
}

How can I do this?

So far I get the tags page, with

serializers.py

class TagsSerializer(TaggitSerializer, serializers.ModelSerializer):
    
    class Meta:
        model = Tag
        fields = (
            '__all__'
        )

        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

views.py

class TagsViewSet(viewsets.ModelViewSet):
    serializer_class = TagsSerializer
    queryset = Tag.objects.all()
    lookup_field = 'slug'

but this only returns the tag with id, name and slug.

Any help is greatly appreciated!

Leonardo
  • 2,439
  • 33
  • 17
  • 31

1 Answers1

0

You can try to write new view that inherits from generics.ListView which can return a filtered list of serialized instance. You need to filter queryset with tag name from url by overriding get_queryset method.

urls.py

urlpatterns = [
    path('', include(router.urls)),
    path('tags/<slug:tag_name>/', MoviesByTagSlugViewSet.as_view()),
]

views.py

from rest_framework import generics


class MoviesByTagSlugViewSet(generics.ListView):
    serializer_class = MovieSerializer
    queryset = Movie.objects.all()
    
    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.filter(tags__name=self.kwargs['tag_name'])
wiaterb
  • 496
  • 3
  • 8