TASK-001: Setup FastAPI project structure
- Fixed main.py to include all route routers (posts, users, comments, feed) - Renamed app/models.py to app/schemas.py and split into proper schema modules - Fixed schema imports in routes - Updated app/models/__init__.py to properly export SQLAlchemy models - Fixed database imports in route files - App imports and runs correctly
This commit is contained in:
17
app/main.py
17
app/main.py
@@ -1,12 +1,18 @@
|
||||
"""FastAPI application entry point."""
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from app.core.config import settings
|
||||
from app.db.database import engine, Base
|
||||
from app.routers.auth import router as auth_router
|
||||
from app.routers.auth import router as auth_router # noqa: F401
|
||||
from app.routes.posts import router as posts_router
|
||||
from app.routes.users import router as users_router
|
||||
from app.routes.comments import router as comments_router
|
||||
from app.routes.feed import router as feed_router
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
@@ -37,6 +43,15 @@ app.add_middleware(
|
||||
|
||||
# Include routers
|
||||
app.include_router(auth_router)
|
||||
app.include_router(posts_router)
|
||||
app.include_router(users_router)
|
||||
app.include_router(comments_router)
|
||||
app.include_router(feed_router)
|
||||
|
||||
# Mount static files for uploads
|
||||
UPLOAD_DIR = Path(__file__).parent.parent / "uploads"
|
||||
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
app.mount("/uploads", StaticFiles(directory=str(UPLOAD_DIR)), name="uploads")
|
||||
|
||||
|
||||
@app.get("/")
|
||||
|
||||
109
app/models.py
109
app/models.py
@@ -1,109 +0,0 @@
|
||||
"""Pydantic models for SocialPhoto API."""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, EmailStr, Field
|
||||
|
||||
|
||||
# Auth Models
|
||||
class UserRegister(BaseModel):
|
||||
"""Request model for user registration."""
|
||||
username: str = Field(..., min_length=3, max_length=50)
|
||||
email: EmailStr
|
||||
password: str = Field(..., min_length=6)
|
||||
|
||||
|
||||
class UserLogin(BaseModel):
|
||||
"""Request model for user login."""
|
||||
username: str
|
||||
password: str
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
"""Response model for JWT token."""
|
||||
access_token: str
|
||||
token_type: str = "bearer"
|
||||
|
||||
|
||||
# User Models
|
||||
class UserBase(BaseModel):
|
||||
"""Base user model."""
|
||||
username: str
|
||||
email: str
|
||||
avatar_url: Optional[str] = "/static/default-avatar.png"
|
||||
bio: Optional[str] = ""
|
||||
|
||||
|
||||
class UserResponse(UserBase):
|
||||
"""Response model for user data."""
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class UserStats(BaseModel):
|
||||
"""User statistics model."""
|
||||
posts_count: int
|
||||
followers_count: int
|
||||
following_count: int
|
||||
|
||||
|
||||
# Post Models
|
||||
class PostCreate(BaseModel):
|
||||
"""Request model for creating a post."""
|
||||
caption: Optional[str] = ""
|
||||
|
||||
|
||||
class PostResponse(BaseModel):
|
||||
"""Response model for post data."""
|
||||
id: int
|
||||
user_id: int
|
||||
username: str
|
||||
image_url: str
|
||||
caption: str
|
||||
likes_count: int
|
||||
dislikes_count: int
|
||||
comments_count: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class PostDetail(PostResponse):
|
||||
"""Detailed post response with user info."""
|
||||
user: UserResponse
|
||||
|
||||
|
||||
# Comment Models
|
||||
class CommentCreate(BaseModel):
|
||||
"""Request model for creating a comment."""
|
||||
content: str = Field(..., min_length=1, max_length=500)
|
||||
|
||||
|
||||
class CommentResponse(BaseModel):
|
||||
"""Response model for comment data."""
|
||||
id: int
|
||||
post_id: int
|
||||
user_id: int
|
||||
username: str
|
||||
content: str
|
||||
likes_count: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
# Feed Models
|
||||
class FeedResponse(BaseModel):
|
||||
"""Response model for feed."""
|
||||
posts: List[PostResponse]
|
||||
total: int
|
||||
limit: int
|
||||
offset: int
|
||||
|
||||
|
||||
# Error Models
|
||||
class ErrorResponse(BaseModel):
|
||||
"""Standard error response."""
|
||||
detail: str
|
||||
@@ -1,4 +1,6 @@
|
||||
"""Models package."""
|
||||
|
||||
# SQLAlchemy models
|
||||
from app.models.user import User
|
||||
|
||||
__all__ = ["User"]
|
||||
|
||||
@@ -6,8 +6,8 @@ from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
from app.auth import create_access_token, hash_password, verify_password
|
||||
from app.database import get_db, row_to_dict
|
||||
from app.models import Token, UserLogin, UserRegister
|
||||
from app.db.database import get_db, row_to_dict
|
||||
from app.schemas import Token, UserLogin, UserRegister
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["Authentication"])
|
||||
security = HTTPBearer()
|
||||
|
||||
@@ -7,7 +7,7 @@ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
from app.auth import get_current_user_id
|
||||
from app.database import get_db, row_to_dict
|
||||
from app.models import FeedResponse, PostResponse
|
||||
from app.schemas import FeedResponse, PostResponse
|
||||
|
||||
router = APIRouter(prefix="/feed", tags=["Feed"])
|
||||
security = HTTPBearer()
|
||||
|
||||
@@ -12,7 +12,7 @@ from fastapi.responses import FileResponse
|
||||
|
||||
from app.auth import get_current_user_id
|
||||
from app.database import get_db, row_to_dict
|
||||
from app.models import CommentCreate, CommentResponse, PostResponse
|
||||
from app.schemas import CommentCreate, CommentResponse, PostResponse
|
||||
|
||||
router = APIRouter(prefix="/posts", tags=["Posts"])
|
||||
security = HTTPBearer()
|
||||
|
||||
@@ -7,7 +7,7 @@ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
from app.auth import get_current_user_id
|
||||
from app.database import get_db, row_to_dict
|
||||
from app.models import PostResponse, UserResponse, UserStats
|
||||
from app.schemas import PostResponse, UserResponse, UserStats
|
||||
|
||||
router = APIRouter(prefix="/users", tags=["Users"])
|
||||
security = HTTPBearer()
|
||||
|
||||
@@ -6,4 +6,24 @@ from app.schemas.auth import (
|
||||
UserResponse,
|
||||
)
|
||||
|
||||
__all__ = ["Token", "UserLogin", "UserRegister", "UserResponse"]
|
||||
# Post schemas
|
||||
from app.schemas.post import CommentCreate, CommentResponse, PostResponse
|
||||
|
||||
# User schemas
|
||||
from app.schemas.user import UserBase, UserStats
|
||||
|
||||
# Feed schemas
|
||||
from app.schemas.feed import FeedResponse
|
||||
|
||||
__all__ = [
|
||||
"Token",
|
||||
"UserLogin",
|
||||
"UserRegister",
|
||||
"UserResponse",
|
||||
"CommentCreate",
|
||||
"CommentResponse",
|
||||
"PostResponse",
|
||||
"UserBase",
|
||||
"UserStats",
|
||||
"FeedResponse",
|
||||
]
|
||||
|
||||
14
app/schemas/feed.py
Normal file
14
app/schemas/feed.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""Feed schemas for SocialPhoto API."""
|
||||
from typing import List
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.schemas.post import PostResponse
|
||||
|
||||
|
||||
class FeedResponse(BaseModel):
|
||||
"""Response model for feed."""
|
||||
posts: List[PostResponse]
|
||||
total: int
|
||||
limit: int
|
||||
offset: int
|
||||
48
app/schemas/post.py
Normal file
48
app/schemas/post.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""Post schemas for SocialPhoto API."""
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class PostCreate(BaseModel):
|
||||
"""Request model for creating a post."""
|
||||
caption: Optional[str] = ""
|
||||
|
||||
|
||||
class PostResponse(BaseModel):
|
||||
"""Response model for post data."""
|
||||
id: int
|
||||
user_id: int
|
||||
username: str
|
||||
image_url: str
|
||||
caption: str
|
||||
likes_count: int
|
||||
dislikes_count: int
|
||||
comments_count: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class PostDetail(PostResponse):
|
||||
"""Detailed post response with user info."""
|
||||
user: "UserResponse" # noqa: F821
|
||||
|
||||
|
||||
class CommentCreate(BaseModel):
|
||||
"""Request model for creating a comment."""
|
||||
content: str = Field(..., min_length=1, max_length=500)
|
||||
|
||||
|
||||
class CommentResponse(BaseModel):
|
||||
"""Response model for comment data."""
|
||||
id: int
|
||||
post_id: int
|
||||
user_id: int
|
||||
username: str
|
||||
content: str
|
||||
likes_count: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
20
app/schemas/user.py
Normal file
20
app/schemas/user.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""User schemas for SocialPhoto API."""
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
"""Base user model."""
|
||||
username: str
|
||||
email: str
|
||||
avatar_url: Optional[str] = "/static/default-avatar.png"
|
||||
bio: Optional[str] = ""
|
||||
|
||||
|
||||
class UserStats(BaseModel):
|
||||
"""User statistics model."""
|
||||
posts_count: int
|
||||
followers_count: int
|
||||
following_count: int
|
||||
Reference in New Issue
Block a user