Files
guilan-ace-backend/apps/blog/api/schemas.py
Amirhossein Khalili b4903f7cb1
Some checks failed
Backend CI/CD / test (push) Has been cancelled
Backend CI/CD / deploy (push) Has been cancelled
F(backend): add public media derivatives pipeline
2026-05-20 14:26:51 +03:30

125 lines
3.7 KiB
Python

"""Blog API schemas."""
from ninja import Schema, ModelSchema
from typing import Optional, List
from datetime import datetime
from apps.blog.models import Category, Tag, Comment
from core.media import PREVIEW_VARIANT, THUMBNAIL_VARIANT, derivative_url
class CategorySchema(ModelSchema):
class Config:
model = Category
model_fields = ['id', 'name', 'slug', 'description']
class TagSchema(ModelSchema):
class Config:
model = Tag
model_fields = ['id', 'name', 'slug']
class AuthorSchema(Schema):
id: int
username: str
first_name: str
last_name: str
profile_picture: Optional[str] = None
profile_picture_thumbnail_url: Optional[str] = None
profile_picture_preview_url: Optional[str] = None
@staticmethod
def resolve_profile_picture(obj, context):
request = context['request']
if obj.profile_picture and hasattr(obj.profile_picture, 'url'):
return request.build_absolute_uri(obj.profile_picture.url)
return None
@staticmethod
def resolve_profile_picture_thumbnail_url(obj, context):
request = context["request"]
url = derivative_url(obj.profile_picture, THUMBNAIL_VARIANT)
return request.build_absolute_uri(url) if url else None
@staticmethod
def resolve_profile_picture_preview_url(obj, context):
request = context["request"]
url = derivative_url(obj.profile_picture, PREVIEW_VARIANT)
return request.build_absolute_uri(url) if url else None
class PostListSchema(Schema):
id: int
title: str
slug: str
excerpt: str
author: AuthorSchema
featured_image: Optional[str] = None
absolute_featured_image_url: Optional[str] = None
absolute_featured_image_thumbnail_url: Optional[str] = None
absolute_featured_image_preview_url: Optional[str] = None
status: str
published_at: Optional[datetime] = None
category: Optional[CategorySchema] = None
tags: List[TagSchema]
is_featured: bool
created_at: datetime
reading_time: int
@staticmethod
def resolve_absolute_featured_image_url(obj, context):
request = context["request"]
if obj.featured_image and hasattr(obj.featured_image, "url"):
return request.build_absolute_uri(obj.featured_image.url)
return None
@staticmethod
def resolve_absolute_featured_image_thumbnail_url(obj, context):
request = context["request"]
url = derivative_url(obj.featured_image, THUMBNAIL_VARIANT)
return request.build_absolute_uri(url) if url else None
@staticmethod
def resolve_absolute_featured_image_preview_url(obj, context):
request = context["request"]
url = derivative_url(obj.featured_image, PREVIEW_VARIANT)
return request.build_absolute_uri(url) if url else None
class PostDetailSchema(PostListSchema):
content: str
content_html: str
class PostCreateSchema(Schema):
title: str
content: str
excerpt: Optional[str] = None
category_id: Optional[int] = None
tag_ids: Optional[List[int]] = []
status: str = "draft"
is_featured: bool = False
class CommentSchema(ModelSchema):
author: AuthorSchema
replies: List['CommentSchema'] = []
post_id: int
post_title: str
post_slug: str
class Config:
model = Comment
model_fields = ['id', 'content', 'created_at', 'is_approved']
@staticmethod
def resolve_post_id(obj):
return obj.post_id
@staticmethod
def resolve_post_title(obj):
return obj.post.title
@staticmethod
def resolve_post_slug(obj):
return obj.post.slug
class CommentCreateSchema(Schema):
content: str
parent_id: Optional[int] = None