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)]