from django.db.models import Prefetch, Q from django.shortcuts import get_object_or_404 from django.urls import path from ninja import NinjaAPI, Router from blog import api as reference from blog.models import Post, Tag from blog.schemas import ( CommentCreateOut, PostCreateOut, PostDetailOut, PostListOut, UserDetailOut, ) router = Router() def eager(query): return ( query.select_related("author") .only( "id", "title", "view_count", "created_at", "author__id", "author__username", "author__display_name", ) .prefetch_related(Prefetch("tags", queryset=Tag.objects.only("id", "name", "slug"))) ) @router.get("/posts", response=list[PostListOut]) def list_posts(request): posts = eager(Post.objects.filter(is_published=True).order_by("-created_at")) return [reference._serialize_post_list(p) for p in posts] @router.get("/posts/search", response=list[PostListOut]) def search_posts(request, q: str): posts = eager(Post.objects.filter( Q(title__icontains=q) | Q(body__icontains=q), is_published=True, ).order_by("-created_at")) return [reference._serialize_post_list(p) for p in posts] @router.get("/posts/by-tag/{slug}", response=list[PostListOut]) def posts_by_tag(request, slug: str): tag = get_object_or_404(Tag, slug=slug) posts = eager(tag.posts.filter(is_published=True).order_by("-created_at")) return [reference._serialize_post_list(p) for p in posts] # Reuse original handlers for unchanged endpoints and their exact failure paths. router.get("/posts/{post_id}", response=PostDetailOut)(reference.get_post) router.post("/posts", response=PostCreateOut)(reference.create_post) router.post("/posts/{post_id}/comments", response=CommentCreateOut)(reference.create_comment) router.get("/users/find", response=UserDetailOut)(reference.find_user_by_email) router.get("/users/{user_id}", response=UserDetailOut)(reference.get_user) api = NinjaAPI() api.add_router("/", router) urlpatterns = [path("api/", api.urls)]