add pydantic on backend
This commit is contained in:
parent
abce2bb6ef
commit
580d04d1e7
4 changed files with 94 additions and 15 deletions
|
|
@ -1,10 +1,13 @@
|
|||
import time
|
||||
from decimal import Decimal
|
||||
from pydantic import ValidationError
|
||||
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token, create_refresh_token
|
||||
from app import db
|
||||
from app.models import User, Product, OrderItem, Order
|
||||
from app.celery import celery
|
||||
from app.schemas import ProductCreateRequest, ProductResponse
|
||||
|
||||
api_bp = Blueprint("api", __name__)
|
||||
|
||||
|
|
@ -104,21 +107,28 @@ def create_product():
|
|||
if not user or not user.is_admin:
|
||||
return jsonify({"error": "Admin access required"}), 403
|
||||
|
||||
data = request.get_json()
|
||||
|
||||
product = Product(
|
||||
name=data["name"],
|
||||
description=data.get("description"),
|
||||
price=data["price"],
|
||||
stock=data.get("stock", 0),
|
||||
image_url=data.get("image_url"),
|
||||
category=data.get("category")
|
||||
)
|
||||
|
||||
db.session.add(product)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify(product.to_dict()), 201
|
||||
try:
|
||||
# Validate request data using Pydantic schema
|
||||
product_data = ProductCreateRequest(**request.get_json())
|
||||
|
||||
product = Product(
|
||||
name=product_data.name,
|
||||
description=product_data.description,
|
||||
price=product_data.price,
|
||||
stock=product_data.stock,
|
||||
image_url=product_data.image_url,
|
||||
category=product_data.category
|
||||
)
|
||||
|
||||
db.session.add(product)
|
||||
db.session.commit()
|
||||
|
||||
# Use Pydantic schema for response
|
||||
response = ProductResponse.model_validate(product)
|
||||
return jsonify(response.model_dump()), 201
|
||||
|
||||
except ValidationError as e:
|
||||
return jsonify({"error": "Validation error", "details": e.errors()}), 400
|
||||
|
||||
|
||||
@api_bp.route("/products/<int:product_id>", methods=["PUT"])
|
||||
|
|
|
|||
4
backend/app/schemas/__init__.py
Normal file
4
backend/app/schemas/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
"""Pydantic schemas for request/response validation"""
|
||||
from app.schemas.product import ProductCreateRequest, ProductResponse
|
||||
|
||||
__all__ = ["ProductCreateRequest", "ProductResponse"]
|
||||
64
backend/app/schemas/product.py
Normal file
64
backend/app/schemas/product.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
"""Pydantic schemas for Product model"""
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class ProductCreateRequest(BaseModel):
|
||||
"""Schema for creating a new product"""
|
||||
name: str = Field(..., min_length=1, max_length=200, description="Product name")
|
||||
description: Optional[str] = Field(None, description="Product description")
|
||||
price: Decimal = Field(..., gt=0, description="Product price (must be greater than 0)")
|
||||
stock: int = Field(default=0, ge=0, description="Product stock quantity")
|
||||
image_url: Optional[str] = Field(None, max_length=500, description="Product image URL")
|
||||
category: Optional[str] = Field(None, description="Product category")
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"name": "Handcrafted Wooden Bowl",
|
||||
"description": "A beautiful handcrafted bowl made from oak",
|
||||
"price": 45.99,
|
||||
"stock": 10,
|
||||
"image_url": "https://example.com/bowl.jpg",
|
||||
"category": "Woodwork"
|
||||
}
|
||||
}
|
||||
|
||||
@field_validator("price")
|
||||
@classmethod
|
||||
def validate_price(cls, v: Decimal) -> Decimal:
|
||||
"""Validate that price has at most 2 decimal places"""
|
||||
if v.as_tuple().exponent < -2:
|
||||
raise ValueError("Price must have at most 2 decimal places")
|
||||
return v
|
||||
|
||||
|
||||
class ProductResponse(BaseModel):
|
||||
"""Schema for product response"""
|
||||
id: int
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
stock: int
|
||||
image_url: Optional[str] = None
|
||||
is_active: bool
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"id": 1,
|
||||
"name": "Handcrafted Wooden Bowl",
|
||||
"description": "A beautiful handcrafted bowl made from oak",
|
||||
"price": 45.99,
|
||||
"stock": 10,
|
||||
"image_url": "https://example.com/bowl.jpg",
|
||||
"is_active": True,
|
||||
"created_at": "2024-01-15T10:30:00",
|
||||
"updated_at": "2024-01-15T10:30:00"
|
||||
}
|
||||
}
|
||||
|
|
@ -8,3 +8,4 @@ python-dotenv==1.0.0
|
|||
Werkzeug==3.0.1
|
||||
SQLAlchemy==2.0.23
|
||||
celery[redis]==5.3.6
|
||||
pydantic==2.5.3
|
||||
|
|
|
|||
Loading…
Reference in a new issue