Update generated backend for blog_app with entities: posts, comments, tags, user
This commit is contained in:
parent
63cd866f1a
commit
8f00dcfee4
49
app/api/core/dependencies/dependencies.py
Normal file
49
app/api/core/dependencies/dependencies.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
```python
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True)
|
||||||
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
|
||||||
|
def get_db() -> Generator:
|
||||||
|
try:
|
||||||
|
db = SessionLocal()
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. We import the necessary modules:
|
||||||
|
- `typing` for type hints
|
||||||
|
- `sqlalchemy` for creating the database engine and session
|
||||||
|
- `app.core.config` for accessing the database URI from the application settings
|
||||||
|
|
||||||
|
2. We create a SQLAlchemy engine instance using the database URI from the application settings (`settings.SQLALCHEMY_DATABASE_URI`). The `pool_pre_ping=True` option ensures that the connection pool is pinged to prevent stale connections.
|
||||||
|
|
||||||
|
3. We create a `SessionLocal` class using the `sessionmaker` function from SQLAlchemy. This class will be used to create database sessions.
|
||||||
|
|
||||||
|
4. The `get_db` function is a generator function that creates a new database session for each request. It yields the session, and when the request is complete, it closes the session automatically.
|
||||||
|
|
||||||
|
This `dependencies.py` file can be used in the FastAPI application to provide a database session to the API endpoints. You can import the `get_db` function in your API routes and use it as a dependency:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
from app.api.core.dependencies import get_db
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
def read_root(db=Depends(get_db)):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
By using the `Depends` function from FastAPI, the `get_db` function will be called for each request, providing a new database session. This session can be used within the API route to interact with the database.
|
||||||
|
|
||||||
|
Note: You'll need to make sure that the `app.core.config` module is correctly configured with the appropriate database URI for your SQLite database.
|
40
app/api/core/middleware/activity_tracker.py
Normal file
40
app/api/core/middleware/activity_tracker.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
```python
|
||||||
|
|
||||||
|
from fastapi import Request, Response
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
from starlette.datastructures import MutableHeaders
|
||||||
|
import time
|
||||||
|
|
||||||
|
class ActivityTrackerMiddleware(BaseHTTPMiddleware):
|
||||||
|
async def dispatch(self, request: Request, call_next):
|
||||||
|
start_time = time.time()
|
||||||
|
response = await call_next(request)
|
||||||
|
process_time = time.time() - start_time
|
||||||
|
response.headers["X-Process-Time"] = str(process_time)
|
||||||
|
return response
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
This middleware tracks the processing time for each request and adds an `X-Process-Time` header to the response with the processing time in seconds.
|
||||||
|
|
||||||
|
|
||||||
|
1. `from fastapi import Request, Response`: Import the `Request` and `Response` classes from FastAPI.
|
||||||
|
2. `from starlette.middleware.base import BaseHTTPMiddleware`: Import the `BaseHTTPMiddleware` class from Starlette.
|
||||||
|
3. `from starlette.datastructures import MutableHeaders`: Import the `MutableHeaders` class from Starlette for modifying response headers.
|
||||||
|
4. `import time`: Import the `time` module for measuring processing time.
|
||||||
|
5. `class ActivityTrackerMiddleware(BaseHTTPMiddleware):`: Define a new middleware class `ActivityTrackerMiddleware` that inherits from `BaseHTTPMiddleware`.
|
||||||
|
6. `async def dispatch(self, request: Request, call_next):`: Implement the `dispatch` method, which is called for each incoming request.
|
||||||
|
7. `start_time = time.time()`: Record the start time of the request.
|
||||||
|
8. `response = await call_next(request)`: Call the next middleware or route handler and await the response.
|
||||||
|
9. `process_time = time.time() - start_time`: Calculate the processing time by subtracting the start time from the current time.
|
||||||
|
10. `response.headers["X-Process-Time"] = str(process_time)`: Add the `X-Process-Time` header to the response with the processing time as a string.
|
||||||
|
11. `return response`: Return the response with the added header.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
app.add_middleware(ActivityTrackerMiddleware)
|
||||||
|
```
|
||||||
|
|
||||||
|
This will add the `ActivityTrackerMiddleware` to your FastAPI application, and the `X-Process-Time` header will be included in the response for each request, showing the processing time in seconds.
|
||||||
|
|
||||||
|
Note: Make sure to create the `app/api/core/middleware/` directory structure if it doesn't already exist in your project.
|
46
app/api/db/database.py
Normal file
46
app/api/db/database.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
```python
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
1. We import the necessary modules from SQLAlchemy: `create_engine`, `declarative_base`, and `sessionmaker`.
|
||||||
|
2. We define the SQLite database URL using the `SQLALCHEMY_DATABASE_URL` variable, which points to the `blog_app.db` file in the current directory.
|
||||||
|
3. We create the SQLAlchemy engine using `create_engine` and pass the `SQLALCHEMY_DATABASE_URL` along with a `connect_args` parameter to handle a SQLite-specific thread issue.
|
||||||
|
4. We create a `SessionLocal` class using `sessionmaker`, which will be used to create database sessions.
|
||||||
|
5. We create a `Base` class using `declarative_base`, which will be used as the base class for all SQLAlchemy models.
|
||||||
|
6. Finally, we define a `get_db` function, which will be used as a dependency in our API routes to get a database session. This function creates a new session, yields it for use, and then closes the session after it's no longer needed.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
from app.api.db.database import get_db
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/blogs")
|
||||||
|
def get_blogs(db: Session = Depends(get_db)):
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, the `get_blogs` route gets a database session using the `get_db` dependency function, which can then be used to interact with the database using SQLAlchemy.
|
38
app/api/v1/models/comments.py
Normal file
38
app/api/v1/models/comments.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
```python
|
||||||
|
from sqlalchemy import Column, ForeignKey, Integer, String, Text
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.sql.sqltypes import TIMESTAMP
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
|
||||||
|
from app.db import Base
|
||||||
|
|
||||||
|
class Comment(Base):
|
||||||
|
__tablename__ = "comments"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
content = Column(Text, nullable=False)
|
||||||
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now())
|
||||||
|
post_id = Column(Integer, ForeignKey("posts.id"), nullable=False)
|
||||||
|
|
||||||
|
post = relationship("Post", back_populates="comments")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Comment(id={self.id}, content='{self.content[:20]}...', post_id={self.post_id})"
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. We import the necessary modules from SQLAlchemy, including `Column`, `ForeignKey`, `Integer`, `String`, `Text`, `relationship`, `TIMESTAMP`, `func`, and `Base` from `app.db`.
|
||||||
|
|
||||||
|
2. The `Comment` class is defined, which inherits from `Base`. This class represents the `comments` table in the database.
|
||||||
|
|
||||||
|
- `id`: An integer primary key column with an index.
|
||||||
|
- `content`: A text column that cannot be null, representing the content of the comment.
|
||||||
|
- `created_at`: A timestamp column with the server's default time as the value when a new row is inserted.
|
||||||
|
- `updated_at`: A timestamp column with the server's default time as the value when a new row is inserted, and updated with the current time whenever the row is updated.
|
||||||
|
- `post_id`: An integer column that is a foreign key referencing the `id` column of the `posts` table. This establishes a one-to-many relationship between posts and comments.
|
||||||
|
|
||||||
|
4. We define a `relationship` between the `Comment` and `Post` models using the `relationship` function from SQLAlchemy. This allows us to access the related post from a comment instance, and vice versa.
|
||||||
|
|
||||||
|
5. The `__repr__` method is defined to provide a string representation of a `Comment` instance, which can be useful for debugging purposes.
|
31
app/api/v1/models/posts.py
Normal file
31
app/api/v1/models/posts.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
```python
|
||||||
|
from sqlalchemy import Column, ForeignKey, Integer, String, Text
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
|
from app.db import Base
|
||||||
|
|
||||||
|
class Post(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("User", back_populates="posts")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Post(id={self.id}, title='{self.title}', content='{self.content[:20]}...')"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- `id`: An integer primary key column with an index.
|
||||||
|
- `title`: A string column that cannot be null.
|
||||||
|
- `content`: A text column that cannot be null.
|
||||||
|
- `user_id`: An integer column that references the `id` column of the `users` table (assuming there is a `User` model defined elsewhere). This column cannot be null.
|
||||||
|
|
||||||
|
The `Post` model also has a relationship with the `User` model via the `user` attribute, which is a bidirectional relationship (assuming the `User` model has a `posts` relationship defined as well).
|
||||||
|
|
||||||
|
The `__repr__` method is defined to provide a string representation of a `Post` instance, which can be useful for debugging purposes.
|
||||||
|
|
||||||
|
Note that you'll need to import the necessary modules from SQLAlchemy and the `Base` class from `app.db` at the top of the file. Additionally, you'll need to create the `users` table (assuming it doesn't exist yet) and define the `User` model accordingly.
|
27
app/api/v1/models/tags.py
Normal file
27
app/api/v1/models/tags.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
```python
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String
|
||||||
|
from app.db.base_class import Base
|
||||||
|
|
||||||
|
class Tag(Base):
|
||||||
|
__tablename__ = "tags"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
name = Column(String, unique=True, index=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Tag(id={self.id}, name='{self.name}')"
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. The `from sqlalchemy import Column, Integer, String` line imports the necessary classes from the SQLAlchemy library to define the table columns.
|
||||||
|
2. The `from app.db.base_class import Base` line imports the `Base` class from the `app.db.base_class` module, which is typically used as a base class for SQLAlchemy models.
|
||||||
|
4. The `__tablename__ = "tags"` line specifies the name of the database table for this model.
|
||||||
|
5. The `id` and `name` lines define the columns of the `tags` table:
|
||||||
|
- `id` is an Integer column, set as the primary key and indexed for efficient querying.
|
||||||
|
- `name` is a String column, set as unique and indexed for efficient querying.
|
||||||
|
|
||||||
|
This `Tag` model can be used in the FastAPI backend to interact with the `tags` table in the SQLite database using SQLAlchemy. You can create, read, update, and delete tag records using this model and the SQLAlchemy ORM (Object-Relational Mapping) functionality.
|
||||||
|
|
||||||
|
Note: Make sure to import and use this `Tag` model in your FastAPI application code as needed.
|
39
app/api/v1/models/user.py
Normal file
39
app/api/v1/models/user.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
```python
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String, Boolean
|
||||||
|
from app.db import Base
|
||||||
|
|
||||||
|
class User(Base):
|
||||||
|
__tablename__ = "users"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
username = Column(String, unique=True, index=True)
|
||||||
|
email = Column(String, unique=True, index=True)
|
||||||
|
hashed_password = Column(String)
|
||||||
|
is_active = Column(Boolean, default=True)
|
||||||
|
is_superuser = Column(Boolean, default=False)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"User(id={self.id}, username='{self.username}', email='{self.email}', is_active={self.is_active}, is_superuser={self.is_superuser})"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- `id`: An integer primary key and index.
|
||||||
|
- `username`: A string representing the user's username, which must be unique and indexed.
|
||||||
|
- `email`: A string representing the user's email address, which must be unique and indexed.
|
||||||
|
- `hashed_password`: A string representing the hashed password of the user.
|
||||||
|
- `is_active`: A boolean indicating whether the user is active or not, with a default value of `True`.
|
||||||
|
- `is_superuser`: A boolean indicating whether the user is a superuser or not, with a default value of `False`.
|
||||||
|
|
||||||
|
The `__repr__` method is defined to provide a string representation of the `User` object when printed.
|
||||||
|
|
||||||
|
Make sure to import the necessary modules and classes at the top of the file:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from sqlalchemy import Column, Integer, String, Boolean
|
||||||
|
from app.db import Base
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, `Column`, `Integer`, `String`, and `Boolean` are imported from the `sqlalchemy` module, and `Base` is imported from `app.db`, which is assumed to be the base class for SQLAlchemy models in your FastAPI application.
|
||||||
|
|
||||||
|
Note: This code assumes that you have already set up the necessary database connections and configurations for your FastAPI application using SQLAlchemy and SQLite.
|
@ -0,0 +1,27 @@
|
|||||||
|
```python
|
||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from .posts import router as posts_router
|
||||||
|
from .comments import router as comments_router
|
||||||
|
from .tags import router as tags_router
|
||||||
|
from .users import router as users_router
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
router.include_router(posts_router, prefix="/posts", tags=["posts"])
|
||||||
|
router.include_router(comments_router, prefix="/comments", tags=["comments"])
|
||||||
|
router.include_router(tags_router, prefix="/tags", tags=["tags"])
|
||||||
|
router.include_router(users_router, prefix="/users", tags=["users"])
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. We import the `APIRouter` class from the `fastapi` library to create a new router instance.
|
||||||
|
2. We import the routers for posts, comments, tags, and users from their respective modules (`posts.py`, `comments.py`, `tags.py`, and `users.py`).
|
||||||
|
3. We create a new `APIRouter` instance called `router`.
|
||||||
|
4. We include each of the imported routers using the `include_router` method of the main `router` instance.
|
||||||
|
- The `prefix` parameter sets the URL prefix for each router.
|
||||||
|
- The `tags` parameter is used for grouping the routes in the Swagger UI documentation.
|
||||||
|
5. This `__init__.py` file will be imported by the main FastAPI application to include all the routes from the different modules.
|
||||||
|
|
||||||
|
Note: Make sure that the `posts.py`, `comments.py`, `tags.py`, and `users.py` modules exist in the same directory (`app/api/v1/routes/`) and contain the respective router instances named `router`.
|
65
app/api/v1/routes/comments.py
Normal file
65
app/api/v1/routes/comments.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
```python
|
||||||
|
from typing import List
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.db import get_db
|
||||||
|
from app.models import Comment
|
||||||
|
from app.schemas import CommentCreate, CommentResponse
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/comments",
|
||||||
|
tags=["Comments"],
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.post("/", response_model=CommentResponse, status_code=201)
|
||||||
|
def create_comment(comment: CommentCreate, db: Session = Depends(get_db)):
|
||||||
|
db_comment = Comment(**comment.dict())
|
||||||
|
db.add(db_comment)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_comment)
|
||||||
|
return db_comment
|
||||||
|
|
||||||
|
@router.get("/", response_model=List[CommentResponse])
|
||||||
|
def get_all_comments(db: Session = Depends(get_db)):
|
||||||
|
comments = db.query(Comment).all()
|
||||||
|
return comments
|
||||||
|
|
||||||
|
@router.get("/{comment_id}", response_model=CommentResponse)
|
||||||
|
def get_comment(comment_id: int, db: Session = Depends(get_db)):
|
||||||
|
comment = db.query(Comment).filter(Comment.id == comment_id).first()
|
||||||
|
if not comment:
|
||||||
|
raise HTTPException(status_code=404, detail="Comment not found")
|
||||||
|
return comment
|
||||||
|
|
||||||
|
@router.put("/{comment_id}", response_model=CommentResponse)
|
||||||
|
def update_comment(comment_id: int, comment: CommentCreate, db: Session = Depends(get_db)):
|
||||||
|
db_comment = db.query(Comment).filter(Comment.id == comment_id).first()
|
||||||
|
if not db_comment:
|
||||||
|
raise HTTPException(status_code=404, detail="Comment not found")
|
||||||
|
for field, value in comment.dict().items():
|
||||||
|
setattr(db_comment, field, value)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_comment)
|
||||||
|
return db_comment
|
||||||
|
|
||||||
|
@router.delete("/{comment_id}", status_code=204)
|
||||||
|
def delete_comment(comment_id: int, db: Session = Depends(get_db)):
|
||||||
|
comment = db.query(Comment).filter(Comment.id == comment_id).first()
|
||||||
|
if not comment:
|
||||||
|
raise HTTPException(status_code=404, detail="Comment not found")
|
||||||
|
db.delete(comment)
|
||||||
|
db.commit()
|
||||||
|
return None
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- `POST /comments/`: Create a new comment
|
||||||
|
- `GET /comments/`: Get all comments
|
||||||
|
- `GET /comments/{comment_id}`: Get a single comment
|
||||||
|
- `PUT /comments/{comment_id}`: Update a comment
|
||||||
|
- `DELETE /comments/{comment_id}`: Delete a comment
|
||||||
|
|
||||||
|
The endpoints use SQLAlchemy models and Pydantic schemas for data validation and serialization. The `get_db` dependency is used to get a database session.
|
||||||
|
|
||||||
|
Note: Make sure you have the appropriate models and schemas defined in your project, and that the `get_db` function is correctly configured to connect to your database.
|
62
app/api/v1/routes/posts.py
Normal file
62
app/api/v1/routes/posts.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
```python
|
||||||
|
from typing import List
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.db import get_db
|
||||||
|
from app.models import Post
|
||||||
|
from app.schemas import PostCreate, PostResponse
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/posts", response_model=List[PostResponse])
|
||||||
|
def get_posts(db: Session = Depends(get_db)):
|
||||||
|
posts = db.query(Post).all()
|
||||||
|
return posts
|
||||||
|
|
||||||
|
@router.post("/posts", response_model=PostResponse)
|
||||||
|
def create_post(post: PostCreate, db: Session = Depends(get_db)):
|
||||||
|
new_post = Post(**post.dict())
|
||||||
|
db.add(new_post)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(new_post)
|
||||||
|
return new_post
|
||||||
|
|
||||||
|
@router.get("/posts/{post_id}", response_model=PostResponse)
|
||||||
|
def get_post(post_id: int, db: Session = Depends(get_db)):
|
||||||
|
post = db.query(Post).filter(Post.id == post_id).first()
|
||||||
|
if not post:
|
||||||
|
raise HTTPException(status_code=404, detail="Post not found")
|
||||||
|
return post
|
||||||
|
|
||||||
|
@router.put("/posts/{post_id}", response_model=PostResponse)
|
||||||
|
def update_post(post_id: int, post: PostCreate, db: Session = Depends(get_db)):
|
||||||
|
db_post = db.query(Post).filter(Post.id == post_id).first()
|
||||||
|
if not db_post:
|
||||||
|
raise HTTPException(status_code=404, detail="Post not found")
|
||||||
|
for field, value in post.dict().items():
|
||||||
|
setattr(db_post, field, value)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_post)
|
||||||
|
return db_post
|
||||||
|
|
||||||
|
@router.delete("/posts/{post_id}", response_model=None)
|
||||||
|
def delete_post(post_id: int, db: Session = Depends(get_db)):
|
||||||
|
post = db.query(Post).filter(Post.id == post_id).first()
|
||||||
|
if not post:
|
||||||
|
raise HTTPException(status_code=404, detail="Post not found")
|
||||||
|
db.delete(post)
|
||||||
|
db.commit()
|
||||||
|
return
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- `GET /posts`: Retrieve a list of all posts
|
||||||
|
- `POST /posts`: Create a new post
|
||||||
|
- `GET /posts/{post_id}`: Retrieve a specific post by ID
|
||||||
|
- `PUT /posts/{post_id}`: Update a specific post by ID
|
||||||
|
- `DELETE /posts/{post_id}`: Delete a specific post by ID
|
||||||
|
|
||||||
|
It uses the `Post` model from `app.models` and the `PostCreate` and `PostResponse` schemas from `app.schemas`. The `get_db` function from `app.db` is used to obtain a database session.
|
||||||
|
|
||||||
|
Note that you'll need to import the required models, schemas, and database dependencies in your actual application.
|
62
app/api/v1/routes/tags.py
Normal file
62
app/api/v1/routes/tags.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
```python
|
||||||
|
from typing import List
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.db.session import get_db
|
||||||
|
from app.models.tag import Tag
|
||||||
|
from app.schemas.tag import TagCreate, TagUpdate, TagOut
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/tags/", response_model=List[TagOut])
|
||||||
|
def read_tags(db: Session = Depends(get_db), skip: int = 0, limit: int = 100):
|
||||||
|
tags = db.query(Tag).offset(skip).limit(limit).all()
|
||||||
|
return tags
|
||||||
|
|
||||||
|
@router.post("/tags/", response_model=TagOut)
|
||||||
|
def create_tag(tag: TagCreate, db: Session = Depends(get_db)):
|
||||||
|
db_tag = Tag(name=tag.name)
|
||||||
|
db.add(db_tag)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_tag)
|
||||||
|
return db_tag
|
||||||
|
|
||||||
|
@router.get("/tags/{tag_id}", response_model=TagOut)
|
||||||
|
def read_tag(tag_id: int, db: Session = Depends(get_db)):
|
||||||
|
db_tag = db.query(Tag).filter(Tag.id == tag_id).first()
|
||||||
|
if not db_tag:
|
||||||
|
raise HTTPException(status_code=404, detail="Tag not found")
|
||||||
|
return db_tag
|
||||||
|
|
||||||
|
@router.put("/tags/{tag_id}", response_model=TagOut)
|
||||||
|
def update_tag(tag_id: int, tag: TagUpdate, db: Session = Depends(get_db)):
|
||||||
|
db_tag = db.query(Tag).filter(Tag.id == tag_id).first()
|
||||||
|
if not db_tag:
|
||||||
|
raise HTTPException(status_code=404, detail="Tag not found")
|
||||||
|
update_data = tag.dict(exclude_unset=True)
|
||||||
|
for key, value in update_data.items():
|
||||||
|
setattr(db_tag, key, value)
|
||||||
|
db.add(db_tag)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_tag)
|
||||||
|
return db_tag
|
||||||
|
|
||||||
|
@router.delete("/tags/{tag_id}", response_model=None)
|
||||||
|
def delete_tag(tag_id: int, db: Session = Depends(get_db)):
|
||||||
|
db_tag = db.query(Tag).filter(Tag.id == tag_id).first()
|
||||||
|
if not db_tag:
|
||||||
|
raise HTTPException(status_code=404, detail="Tag not found")
|
||||||
|
db.delete(db_tag)
|
||||||
|
db.commit()
|
||||||
|
return None
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- `GET /tags/`: Get a list of tags with optional `skip` and `limit` parameters.
|
||||||
|
- `POST /tags/`: Create a new tag.
|
||||||
|
- `GET /tags/{tag_id}`: Get a specific tag by ID.
|
||||||
|
- `PUT /tags/{tag_id}`: Update a specific tag by ID.
|
||||||
|
- `DELETE /tags/{tag_id}`: Delete a specific tag by ID.
|
||||||
|
|
||||||
|
The endpoints use SQLAlchemy models and Pydantic schemas for data validation and serialization. The `get_db` dependency is used to get a database session.
|
64
app/api/v1/routes/user.py
Normal file
64
app/api/v1/routes/user.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from typing import List
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.db import get_db
|
||||||
|
from app.models.user import User as UserModel
|
||||||
|
from app.schemas.user import User, UserCreate, UserUpdate
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/users", response_model=User, status_code=201)
|
||||||
|
def create_user(user: UserCreate, db: Session = Depends(get_db)):
|
||||||
|
db_user = UserModel(**user.dict())
|
||||||
|
db.add(db_user)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_user)
|
||||||
|
return db_user
|
||||||
|
|
||||||
|
@router.get("/users", response_model=List[User])
|
||||||
|
def get_users(db: Session = Depends(get_db)):
|
||||||
|
users = db.query(UserModel).all()
|
||||||
|
return users
|
||||||
|
|
||||||
|
@router.get("/users/{user_id}", response_model=User)
|
||||||
|
def get_user(user_id: int, db: Session = Depends(get_db)):
|
||||||
|
db_user = db.query(UserModel).filter(UserModel.id == user_id).first()
|
||||||
|
if not db_user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
return db_user
|
||||||
|
|
||||||
|
@router.put("/users/{user_id}", response_model=User)
|
||||||
|
def update_user(user_id: int, user: UserUpdate, db: Session = Depends(get_db)):
|
||||||
|
db_user = db.query(UserModel).filter(UserModel.id == user_id).first()
|
||||||
|
if not db_user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
update_data = user.dict(exclude_unset=True)
|
||||||
|
for key, value in update_data.items():
|
||||||
|
setattr(db_user, key, value)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_user)
|
||||||
|
return db_user
|
||||||
|
|
||||||
|
@router.delete("/users/{user_id}", status_code=204)
|
||||||
|
def delete_user(user_id: int, db: Session = Depends(get_db)):
|
||||||
|
db_user = db.query(UserModel).filter(UserModel.id == user_id).first()
|
||||||
|
if not db_user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
db.delete(db_user)
|
||||||
|
db.commit()
|
||||||
|
return {"message": "User deleted successfully"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The endpoints are:
|
||||||
|
|
||||||
|
1. `POST /users`: Creates a new user based on the provided `UserCreate` model data.
|
||||||
|
2. `GET /users`: Retrieves a list of all users.
|
||||||
|
3. `GET /users/{user_id}`: Retrieves a specific user by ID.
|
||||||
|
4. `PUT /users/{user_id}`: Updates an existing user with the provided `UserUpdate` model data.
|
||||||
|
5. `DELETE /users/{user_id}`: Deletes a user by ID.
|
||||||
|
|
||||||
|
The code uses dependency injection to obtain a SQLAlchemy database session from the `get_db` function (assumed to be defined elsewhere). It also handles HTTP exceptions for cases where a user is not found (404 Not Found).
|
||||||
|
|
||||||
|
Note that this is a basic implementation, and you may need to add additional functionality, such as authentication, authorization, and input validation, depending on your application's requirements.
|
37
app/api/v1/schemas/comments.py
Normal file
37
app/api/v1/schemas/comments.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
```python
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class CommentBase(BaseModel):
|
||||||
|
content: str
|
||||||
|
|
||||||
|
class CommentCreate(CommentBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CommentUpdate(CommentBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Comment(CommentBase):
|
||||||
|
id: int
|
||||||
|
post_id: int
|
||||||
|
user_id: int
|
||||||
|
created_at: datetime
|
||||||
|
updated_at: Optional[datetime] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. We import the necessary modules: `typing` for type hints, `pydantic` for defining data models, and `datetime` for working with date and time objects.
|
||||||
|
|
||||||
|
|
||||||
|
3. `CommentCreate` inherits from `CommentBase` and is used for creating new comments. It doesn't add any additional fields.
|
||||||
|
|
||||||
|
4. `CommentUpdate` also inherits from `CommentBase` and is used for updating existing comments. It doesn't add any additional fields.
|
||||||
|
|
||||||
|
5. `Comment` inherits from `CommentBase` and represents a complete comment object. It includes fields like `id`, `post_id`, `user_id`, `created_at`, and `updated_at`.
|
||||||
|
|
||||||
|
6. The `Config` class inside `Comment` sets `orm_mode = True`, which allows Pydantic to work with SQLAlchemy models and handle datetime objects correctly.
|
42
app/api/v1/schemas/posts.py
Normal file
42
app/api/v1/schemas/posts.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
```python
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class PostBase(BaseModel):
|
||||||
|
title: str
|
||||||
|
content: str
|
||||||
|
|
||||||
|
class PostCreate(PostBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class PostUpdate(BaseModel):
|
||||||
|
title: Optional[str] = None
|
||||||
|
content: Optional[str] = None
|
||||||
|
|
||||||
|
class PostInDBBase(PostBase):
|
||||||
|
id: int
|
||||||
|
created_at: datetime
|
||||||
|
updated_at: Optional[datetime] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
class Post(PostInDBBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class PostInDB(PostInDBBase):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. We import the necessary modules: `typing` for type hints, `pydantic` for defining data models, and `datetime` for working with date and time.
|
||||||
|
|
||||||
|
|
||||||
|
3. `PostCreate` inherits from `PostBase` and is used for creating a new post.
|
||||||
|
|
||||||
|
|
||||||
|
5. `PostInDBBase` inherits from `PostBase` and adds fields specific to the database representation: `id`, `created_at`, and `updated_at`. The `Config` class is used to enable the ORM mode, which allows Pydantic to work with SQLAlchemy models.
|
||||||
|
|
||||||
|
6. `Post` and `PostInDB` are response schemas that inherit from `PostInDBBase`. These schemas will be used to serialize the data returned from the API.
|
39
app/api/v1/schemas/tags.py
Normal file
39
app/api/v1/schemas/tags.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
```python
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class TagBase(BaseModel):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
class TagCreate(TagBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TagUpdate(TagBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TagInDBBase(TagBase):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
class Tag(TagInDBBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TagInDB(TagInDBBase):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
1. We import the necessary modules: `typing` for type hints, and `pydantic` for defining data models.
|
||||||
|
3. `TagCreate` inherits from `TagBase` and represents the data required to create a new tag.
|
||||||
|
4. `TagUpdate` also inherits from `TagBase` and represents the data required to update an existing tag.
|
||||||
|
5. `TagInDBBase` inherits from `TagBase` and adds an `id` field. It also sets the `orm_mode` configuration option to `True`, which allows Pydantic to work with SQLAlchemy models.
|
||||||
|
6. `Tag` inherits from `TagInDBBase` and represents a tag object as it would be returned from the database.
|
||||||
|
7. `TagInDB` also inherits from `TagInDBBase` and represents a tag object as it would be stored in the database.
|
||||||
|
|
||||||
|
These schemas can be used in the FastAPI application to define request and response models for tag-related operations. For example, the `TagCreate` model can be used as the request body for creating a new tag, while the `Tag` model can be used as the response model for retrieving a tag from the database.
|
||||||
|
|
||||||
|
Note: This implementation assumes that you have already set up the necessary dependencies and project structure for your FastAPI backend. If you need further assistance with integrating these schemas into your application or setting up the database models, please provide more context or specific requirements.
|
39
app/api/v1/schemas/user.py
Normal file
39
app/api/v1/schemas/user.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
```python
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel, EmailStr
|
||||||
|
|
||||||
|
class UserBase(BaseModel):
|
||||||
|
email: Optional[EmailStr] = None
|
||||||
|
is_active: Optional[bool] = True
|
||||||
|
is_superuser: bool = False
|
||||||
|
full_name: Optional[str] = None
|
||||||
|
|
||||||
|
class UserCreate(UserBase):
|
||||||
|
email: EmailStr
|
||||||
|
password: str
|
||||||
|
|
||||||
|
class UserUpdate(UserBase):
|
||||||
|
password: Optional[str] = None
|
||||||
|
|
||||||
|
class UserInDBBase(UserBase):
|
||||||
|
id: Optional[int] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
class User(UserInDBBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UserInDB(UserInDBBase):
|
||||||
|
hashed_password: str
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
1. `UserBase`: Base model for user data with optional fields like `email`, `is_active`, `is_superuser`, and `full_name`.
|
||||||
|
2. `UserCreate`: Model for creating a new user, inheriting from `UserBase` and requiring `email` and `password` fields.
|
||||||
|
3. `UserUpdate`: Model for updating an existing user, inheriting from `UserBase` and allowing an optional `password` field.
|
||||||
|
4. `UserInDBBase`: Base model for user data retrieved from the database, inheriting from `UserBase` and adding an optional `id` field. It also sets the `orm_mode` configuration for working with SQLAlchemy models.
|
||||||
|
5. `User`: Model representing a user object retrieved from the database, inheriting from `UserInDBBase`.
|
||||||
|
6. `UserInDB`: Model representing a user object with a `hashed_password` field, inheriting from `UserInDBBase`.
|
||||||
|
|
||||||
|
These models can be used in various parts of the FastAPI application, such as request/response bodies, database operations, and data validation. Make sure to import the necessary dependencies (`pydantic`, `typing`, and `email_validator`) at the top of the file if they are not already imported.
|
52
main.py
52
main.py
@ -1,7 +1,53 @@
|
|||||||
|
```python
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
from starlette.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
app = FastAPI(title="Generated Backend")
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
origins = [
|
||||||
|
"http://localhost",
|
||||||
|
"http://localhost:8000",
|
||||||
|
]
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=origins,
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
from . import models, routes
|
||||||
|
|
||||||
|
app.include_router(routes.router)
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
def read_root():
|
async def root():
|
||||||
return {"message": "Welcome to the generated backend"}
|
return {"message": "Welcome to the Blog App!"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
1. Imports necessary FastAPI, middleware, and SQLAlchemy modules.
|
||||||
|
2. Creates a FastAPI app instance.
|
||||||
|
3. Configures CORS middleware to allow cross-origin requests from specified origins.
|
||||||
|
4. Sets up the SQLite database connection using SQLAlchemy.
|
||||||
|
5. Imports models and routes after the database configuration to avoid circular imports.
|
||||||
|
6. Includes the routes from the `routes` module.
|
||||||
|
|
||||||
|
|
||||||
|
You can run this FastAPI app using the `uvicorn` command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
This will start the development server and automatically reload it when you make changes to the code.
|
@ -1,4 +1,9 @@
|
|||||||
|
Here's the `requirements.txt` file for the 'blog_app' FastAPI backend with the requested dependencies:
|
||||||
|
```
|
||||||
fastapi
|
fastapi
|
||||||
uvicorn
|
uvicorn
|
||||||
sqlalchemy
|
sqlalchemy
|
||||||
pydantic
|
pydantic
|
||||||
|
loguru
|
||||||
|
```
|
||||||
|
This file lists the required Python packages and their versions (if not specified, the latest version will be installed). You can install these dependencies by running `pip install -r requirements.txt` in your project directory.
|
Loading…
x
Reference in New Issue
Block a user