From 5149eb08c14d34608ce8e4c224ec38a1024b54ff Mon Sep 17 00:00:00 2001 From: Idris Abdurrahman Date: Fri, 21 Mar 2025 11:25:06 +0100 Subject: [PATCH] Update generated backend for blog_app with entities: posts, comments, tags, user --- app/api/core/dependencies/dependencies.py | 9 +++++ app/api/core/middleware/activity_tracker.py | 13 +++++++ app/api/db/database.py | 7 ++++ app/api/v1/models/comments.py | 39 +++++++++++++++++++++ app/api/v1/models/posts.py | 32 +++++++++++++++++ app/api/v1/models/tags.py | 24 +++++++++++++ app/api/v1/models/user.py | 33 +++++++++++++++++ app/api/v1/routes/__init__.py | 3 ++ app/api/v1/routes/comments.py | 9 +++++ app/api/v1/routes/posts.py | 9 +++++ app/api/v1/routes/tags.py | 9 +++++ app/api/v1/routes/user.py | 9 +++++ app/api/v1/schemas/comments.py | 11 ++++++ app/api/v1/schemas/posts.py | 9 +++++ app/api/v1/schemas/tags.py | 11 ++++++ app/api/v1/schemas/user.py | 11 ++++++ main.py | 13 ++++--- requirements.txt | 3 +- 18 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 app/api/core/dependencies/dependencies.py create mode 100644 app/api/core/middleware/activity_tracker.py create mode 100644 app/api/db/database.py create mode 100644 app/api/v1/models/comments.py create mode 100644 app/api/v1/models/posts.py create mode 100644 app/api/v1/models/tags.py create mode 100644 app/api/v1/models/user.py create mode 100644 app/api/v1/routes/comments.py create mode 100644 app/api/v1/routes/posts.py create mode 100644 app/api/v1/routes/tags.py create mode 100644 app/api/v1/routes/user.py create mode 100644 app/api/v1/schemas/comments.py create mode 100644 app/api/v1/schemas/posts.py create mode 100644 app/api/v1/schemas/tags.py create mode 100644 app/api/v1/schemas/user.py diff --git a/app/api/core/dependencies/dependencies.py b/app/api/core/dependencies/dependencies.py new file mode 100644 index 0000000..965f5ff --- /dev/null +++ b/app/api/core/dependencies/dependencies.py @@ -0,0 +1,9 @@ +from sqlalchemy.orm import Session +from app.api.db.database import SessionLocal + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/app/api/core/middleware/activity_tracker.py b/app/api/core/middleware/activity_tracker.py new file mode 100644 index 0000000..3d58305 --- /dev/null +++ b/app/api/core/middleware/activity_tracker.py @@ -0,0 +1,13 @@ +from time import time +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.requests import Request +from starlette.responses import Response +from loguru import logger + +class ActivityTrackerMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + start_time = time() + response: Response = await call_next(request) + process_time = time() - start_time + logger.info(f"Request path: {request.url.path} completed in {process_time:.4f} seconds") + return response \ No newline at end of file diff --git a/app/api/db/database.py b/app/api/db/database.py new file mode 100644 index 0000000..f327867 --- /dev/null +++ b/app/api/db/database.py @@ -0,0 +1,7 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +SQLALCHEMY_DATABASE_URL = 'sqlite:///./blog_app.db' +engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False}) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +Base = declarative_base() diff --git a/app/api/v1/models/comments.py b/app/api/v1/models/comments.py new file mode 100644 index 0000000..48b0387 --- /dev/null +++ b/app/api/v1/models/comments.py @@ -0,0 +1,39 @@ +Here's a `comments.py` file for the `app/api/v1/models/` directory of the `blog_app_x0iat` FastAPI backend: + +from typing import Optional +from sqlalchemy import Column, ForeignKey, Integer, String, Text +from sqlalchemy.orm import relationship +from app.api.db.database import Base + +class Comments(Base): + __tablename__ = "comments" + + id = Column(Integer, primary_key=True, index=True) + content = Column(Text, nullable=False) + post_id = Column(Integer, ForeignKey("posts.id"), nullable=False) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + parent_comment_id = Column(Integer, ForeignKey("comments.id"), nullable=True) + + post = relationship("Posts", back_populates="comments") + user = relationship("Users", back_populates="comments") + parent_comment = relationship("Comments", remote_side=[id], back_populates="replies") + replies = relationship("Comments", back_populates="parent_comment") + + def __repr__(self): + return f"Comment(id={self.id}, content='{self.content[:20]}...', post_id={self.post_id}, user_id={self.user_id})" + +Explanation: + +4. Defined columns for the `Comments` table: + - `id`: Integer primary key with index + - `content`: Text column for the comment content (required) + - `post_id`: Integer foreign key referencing the `posts` table (required) + - `user_id`: Integer foreign key referencing the `users` table (required) + - `parent_comment_id`: Integer foreign key referencing the `comments` table itself (nullable, for nested comments) +5. Defined relationships with other models: + - `post`: One-to-many relationship with the `Posts` model + - `user`: One-to-many relationship with the `Users` model + - `parent_comment`: One-to-many self-referential relationship for nested comments + - `replies`: One-to-many self-referential relationship for nested comments (reverse of `parent_comment`) + +Note: This implementation assumes the existence of `Posts` and `Users` models in the same directory. You may need to adjust the relationship definitions based on the actual structure of your project. \ No newline at end of file diff --git a/app/api/v1/models/posts.py b/app/api/v1/models/posts.py new file mode 100644 index 0000000..f9f2779 --- /dev/null +++ b/app/api/v1/models/posts.py @@ -0,0 +1,32 @@ +Here's the `posts.py` file for the `app/api/v1/models/` directory of the `blog_app` FastAPI backend: + +from typing import Optional +from sqlalchemy import Column, ForeignKey, Integer, String, Text +from sqlalchemy.orm import relationship +from app.api.db.database import Base + +class Posts(Base): + __tablename__ = 'posts' + + id = Column(Integer, primary_key=True, index=True) + title = Column(String, nullable=False) + content = Column(Text, nullable=False) + user_id = Column(Integer, ForeignKey('users.id'), nullable=False) + + user = relationship('Users', back_populates='posts') + + def __repr__(self): + return f"Posts(id={self.id}, title='{self.title}', content='{self.content[:20]}...', user_id={self.user_id})" + +Explanation: + + + + + + + + + + +Note: This code assumes the existence of a `Users` model class in the same directory. If the `Users` model does not exist, you may need to remove or modify the `user` relationship definition accordingly. \ No newline at end of file diff --git a/app/api/v1/models/tags.py b/app/api/v1/models/tags.py new file mode 100644 index 0000000..aac0c0e --- /dev/null +++ b/app/api/v1/models/tags.py @@ -0,0 +1,24 @@ +Here's an example `tags.py` file for the `app/api/v1/models/` directory of the `blog_app` FastAPI project: + +from typing import Optional +from sqlalchemy import Column, ForeignKey, Integer, String +from sqlalchemy.orm import relationship +from app.api.db.database import Base + +class Tags(Base): + __tablename__ = "tags" + + id = Column(Integer, primary_key=True, index=True) + name = Column(String(50), nullable=False, unique=True) + description = Column(String(200), nullable=True) + + posts = relationship("Post", back_populates="tags", secondary="post_tags") + + def __repr__(self): + return f"Tag(id={self.id}, name='{self.name}', description='{self.description}')" + +Explanation: + +5. The `name` column is defined as a `String` with a maximum length of 50 characters, nullable=False (required), and unique=True (no duplicates allowed). + +Note: This code assumes that the `Post` model exists and has a `tags` attribute defined with a back-populates relationship to the `Tags` model. Additionally, the `post_tags` association table should be defined separately to establish the many-to-many relationship between `Tags` and `Post` models. \ No newline at end of file diff --git a/app/api/v1/models/user.py b/app/api/v1/models/user.py new file mode 100644 index 0000000..852be7f --- /dev/null +++ b/app/api/v1/models/user.py @@ -0,0 +1,33 @@ +Here's the `user.py` file for the `app/api/v1/models/` directory of the `blog_app` FastAPI backend: + +from typing import Optional +from sqlalchemy import Column, ForeignKey, Integer, String, Text +from sqlalchemy.orm import relationship +from app.api.db.database import Base + +class User(Base): + __tablename__ = 'user' + + id = Column(Integer, primary_key=True, index=True) + username = Column(String, unique=True, index=True, nullable=False) + email = Column(String, unique=True, index=True, nullable=False) + hashed_password = Column(String, nullable=False) + is_active = Column(Integer, default=1) + bio = Column(Text, nullable=True) + + posts = relationship("Post", back_populates="author") + + def __repr__(self): + return f"User(id={self.id}, username='{self.username}', email='{self.email}')" + +Explanation: + +5. Defined columns for the `User` model: + - `id`: Integer primary key with index + - `username`: String, unique, indexed, and non-nullable + - `email`: String, unique, indexed, and non-nullable + - `hashed_password`: String, non-nullable + - `is_active`: Integer with a default value of 1 + - `bio`: Text, nullable + +Note: This code assumes that the `Post` model is defined in a separate file and imported accordingly. Additionally, you may need to adjust the imports and paths based on your project structure and dependencies. \ No newline at end of file diff --git a/app/api/v1/routes/__init__.py b/app/api/v1/routes/__init__.py index e69de29..4d5194a 100644 --- a/app/api/v1/routes/__init__.py +++ b/app/api/v1/routes/__init__.py @@ -0,0 +1,3 @@ +from fastapi import APIRouter + +router = APIRouter() \ No newline at end of file diff --git a/app/api/v1/routes/comments.py b/app/api/v1/routes/comments.py new file mode 100644 index 0000000..940e1eb --- /dev/null +++ b/app/api/v1/routes/comments.py @@ -0,0 +1,9 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from app.api.core.dependencies import get_db + +router = APIRouter() + +@router.get('/comments/') +def read_comments(db: Session = Depends(get_db)): + return {'message': 'Read comments'} diff --git a/app/api/v1/routes/posts.py b/app/api/v1/routes/posts.py new file mode 100644 index 0000000..717942a --- /dev/null +++ b/app/api/v1/routes/posts.py @@ -0,0 +1,9 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from app.api.core.dependencies import get_db + +router = APIRouter() + +@router.get('/posts/') +def read_posts(db: Session = Depends(get_db)): + return {'message': 'Read posts'} diff --git a/app/api/v1/routes/tags.py b/app/api/v1/routes/tags.py new file mode 100644 index 0000000..928683c --- /dev/null +++ b/app/api/v1/routes/tags.py @@ -0,0 +1,9 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from app.api.core.dependencies import get_db + +router = APIRouter() + +@router.get('/tags/') +def read_tags(db: Session = Depends(get_db)): + return {'message': 'Read tags'} diff --git a/app/api/v1/routes/user.py b/app/api/v1/routes/user.py new file mode 100644 index 0000000..818519d --- /dev/null +++ b/app/api/v1/routes/user.py @@ -0,0 +1,9 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from app.api.core.dependencies import get_db + +router = APIRouter() + +@router.get('/user/') +def read_user(db: Session = Depends(get_db)): + return {'message': 'Read user'} diff --git a/app/api/v1/schemas/comments.py b/app/api/v1/schemas/comments.py new file mode 100644 index 0000000..ce46571 --- /dev/null +++ b/app/api/v1/schemas/comments.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel + +class CommentsBase(BaseModel): + body: str + +class Comments(CommentsBase): + id: int + post_id: int + + class Config: + orm_mode = True \ No newline at end of file diff --git a/app/api/v1/schemas/posts.py b/app/api/v1/schemas/posts.py new file mode 100644 index 0000000..320aa5a --- /dev/null +++ b/app/api/v1/schemas/posts.py @@ -0,0 +1,9 @@ +from pydantic import BaseModel + +class PostsBase(BaseModel): + title: str + content: str + +class Posts(PostsBase): + class Config: + orm_mode = True \ No newline at end of file diff --git a/app/api/v1/schemas/tags.py b/app/api/v1/schemas/tags.py new file mode 100644 index 0000000..92f9fd2 --- /dev/null +++ b/app/api/v1/schemas/tags.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel + +class TagsBase(BaseModel): + name: str + +class Tags(TagsBase): + id: int + name: str + + class Config: + orm_mode = True \ No newline at end of file diff --git a/app/api/v1/schemas/user.py b/app/api/v1/schemas/user.py new file mode 100644 index 0000000..b3cc369 --- /dev/null +++ b/app/api/v1/schemas/user.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel + +class UserBase(BaseModel): + email: str + +class User(UserBase): + id: int + is_active: bool + + class Config: + orm_mode = True \ No newline at end of file diff --git a/main.py b/main.py index dca5c44..bf7adff 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,12 @@ from fastapi import FastAPI +from app.api.db.database import engine, Base +from app.api.v1.routes import router +from app.api.core.middleware.activity_tracker import ActivityTrackerMiddleware -app = FastAPI(title="Generated Backend") +app = FastAPI() +app.add_middleware(ActivityTrackerMiddleware) +app.include_router(router, prefix="/v1") -@app.get("/") -def read_root(): - return {"message": "Welcome to the generated backend"} \ No newline at end of file +@app.on_event("startup") +def startup_event(): + Base.metadata.create_all(bind=engine) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a70e8ac..dce5630 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ fastapi uvicorn sqlalchemy -pydantic \ No newline at end of file +pydantic +loguru