Nested dynamic URLs from different Viewsets

backend noob here.

I have a question about nested URLs in Django/DRF. I want to nested url structure, for example:
site.com/blog/: shows list of blog.
site.com/blog/blog-name/: which shows single blog with name.
site.com/blog/blog-name/posts: shows the post list of the blog.
site.com/blog/blog-name/posts/some-blog-post: single blog post.
site.com/blog/blog-name/posts/some-blog-post/tags: list of tags.
site.com/blog/blog-name/posts/some-blog-post/tags/1: a tag with id = 1.

I have read this answer but it suggest an additional method in BlogViewset. However I need to nest URLs using two different viewsets. Because as you can see this is just initial fields of an userblog system and I want to be able to manage it without having big files.

I have three models, like this:

class TagModel(models.Model):
    tag = models.CharField(max_length=32)

    def __str__(self):
        return self.tag


class BlogModel(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)
    profession = models.CharField(max_length=100)

    class Meta:
        pass

    def __str__(self):
        return self.name


class PostModel(models.Model):
    title = models.CharField(max_length=120)
    content = models.TextField()
    tags = models.ManyToManyField(TagModel)
    blog = models.ForeignKey(BlogModel, on_delete=models.CASCADE, related_name="posts")

    def __str__(self):
        return self.title

This is my viewset for Blogs:

from ..models.blog import BlogModel, PostModel
from ..serializers.blog import BlogSerializer
from rest_framework import viewsets
from rest_framework import mixins
from django.shortcuts import render


class BlogViewset(
    mixins.CreateModelMixin,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    viewsets.GenericViewSet,
):
    queryset = BlogModel.objects.all()
    serializer_class = BlogSerializer

    # Return all blogs in the database
    def list(self, request):
        blogs = BlogModel.objects.all()
        context = {"blogs": blogs}
        return render(request, "blog/home.html", context)

    # Return single blog object
    def retrieve(self, request, pk):
        blog = BlogModel.objects.get(id=pk)
        context = {"blog": blog}
        return render(request, "blog/blog.html", context)

The viewset for blog post is:

from ..models.blog import BlogModel, PostModel
from rest_framework import mixins
from rest_framework import viewsets
from django.shortcuts import render


class BlogPostViewSet(
    mixins.CreateModelMixin,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    viewsets.GenericViewSet,
):
    def list(self, request):
        posts = PostModel.objects.all()
        context = {"posts": posts}
        return render(request, "blog/posts.html", context)

    def retrieve(self, request, pk):
        post = PostModel.objects.get(id=pk)
        context = {"post": post}
        return render(request, "blog/single.html", context)

And last but not least, I have urls.py like this:

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

from blog.viewsets import BlogViewset
from blog.viewsets.post import BlogPostViewSet


blog_router = routers.SimpleRouter()
blog_router.register(r"", BlogViewset, basename="blog")

urlpatterns = [
    path("admin/", admin.site.urls),
    path("blog/", include(blog_router.urls)),
]

Thank you for your answers.

Back to Top