add pydantic on backend

This commit is contained in:
david 2026-02-24 17:17:36 +03:00
parent abce2bb6ef
commit 580d04d1e7
4 changed files with 94 additions and 15 deletions

View file

@ -1,10 +1,13 @@
import time import time
from decimal import Decimal
from pydantic import ValidationError
from flask import Blueprint, request, jsonify from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token, create_refresh_token from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token, create_refresh_token
from app import db from app import db
from app.models import User, Product, OrderItem, Order from app.models import User, Product, OrderItem, Order
from app.celery import celery from app.celery import celery
from app.schemas import ProductCreateRequest, ProductResponse
api_bp = Blueprint("api", __name__) api_bp = Blueprint("api", __name__)
@ -104,21 +107,28 @@ def create_product():
if not user or not user.is_admin: if not user or not user.is_admin:
return jsonify({"error": "Admin access required"}), 403 return jsonify({"error": "Admin access required"}), 403
data = request.get_json() try:
# Validate request data using Pydantic schema
product_data = ProductCreateRequest(**request.get_json())
product = Product( product = Product(
name=data["name"], name=product_data.name,
description=data.get("description"), description=product_data.description,
price=data["price"], price=product_data.price,
stock=data.get("stock", 0), stock=product_data.stock,
image_url=data.get("image_url"), image_url=product_data.image_url,
category=data.get("category") category=product_data.category
) )
db.session.add(product) db.session.add(product)
db.session.commit() db.session.commit()
return jsonify(product.to_dict()), 201 # 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"]) @api_bp.route("/products/<int:product_id>", methods=["PUT"])

View file

@ -0,0 +1,4 @@
"""Pydantic schemas for request/response validation"""
from app.schemas.product import ProductCreateRequest, ProductResponse
__all__ = ["ProductCreateRequest", "ProductResponse"]

View 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"
}
}

View file

@ -8,3 +8,4 @@ python-dotenv==1.0.0
Werkzeug==3.0.1 Werkzeug==3.0.1
SQLAlchemy==2.0.23 SQLAlchemy==2.0.23
celery[redis]==5.3.6 celery[redis]==5.3.6
pydantic==2.5.3