From 95f8acb4861773b3b7713814e53a577b777bf97f Mon Sep 17 00:00:00 2001 From: duyanhehe <duyanhex@gmail.com> Date: Sun, 16 Mar 2025 16:35:41 +0700 Subject: [PATCH] updated save images logic --- app/backend/routes/product.py | 147 ++++++++++++------------- app/backend/routes/shop.py | 52 ++++----- app/core/config.py | 5 + app/static/default/default_product.png | Bin 0 -> 401 bytes app/static/default/default_shop.png | Bin 0 -> 633 bytes 5 files changed, 98 insertions(+), 106 deletions(-) create mode 100644 app/static/default/default_product.png create mode 100644 app/static/default/default_shop.png diff --git a/app/backend/routes/product.py b/app/backend/routes/product.py index daaaf9e..8c16bf7 100644 --- a/app/backend/routes/product.py +++ b/app/backend/routes/product.py @@ -1,10 +1,11 @@ from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form from sqlmodel import Session from datetime import datetime -from backend.models.models import Product, ProductImage, User -from backend.schemas.product import ProductRead, ProductImageRead +from backend.models.models import Product, ProductImage, User, Shop +from backend.schemas.product import ProductRead, ProductUpdate from backend.database import get_session from backend.routes.auth import get_current_user +from core.config import settings import shutil import os @@ -22,7 +23,7 @@ def create_product( stock: int = Form(...), shop_id: int = Form(...), category_id: int = Form(None), - images: UploadFile = File(None), # Ensuring image is correctly set + images: list[UploadFile] = File(None), session: Session = Depends(get_session), ): product = Product( @@ -38,16 +39,33 @@ def create_product( session.commit() session.refresh(product) - # Handling image upload - if images and images.filename: - file_ext = os.path.splitext(images.filename)[1] # Get file extension - file_name = f"product_{product.id}{file_ext}" - file_location = os.path.join(static_dir, file_name) - - with open(file_location, "wb") as buffer: - shutil.copyfileobj(images.file, buffer) - - # Save image record in ProductImage + # Get the shop to create the correct directory + shop = session.get(Shop, shop_id) + if not shop: + raise HTTPException(status_code=404, detail="Shop not found") + + shop_dir = os.path.join(settings.static_dir, f"shop_{shop.name}") + os.makedirs(shop_dir, exist_ok=True) + + product_dir = os.path.join(shop_dir, f"product_{product.name}") + os.makedirs(product_dir, exist_ok=True) + + # Handling multiple image uploads + if images: + for image in images: + if image.filename: + file_location = os.path.join(product_dir, image.filename) + with open(file_location, "wb") as buffer: + shutil.copyfileobj(image.file, buffer) + + # Save image record in ProductImage + product_image = ProductImage( + product_id=product.id, image_url=file_location + ) + session.add(product_image) + session.commit() + else: # Save default image + file_location = os.path.join(settings.static_dir, "default/default_product.png") product_image = ProductImage(product_id=product.id, image_url=file_location) session.add(product_image) session.commit() @@ -69,44 +87,57 @@ def read_product(product_id: int, session: Session = Depends(get_session)): return product -@router.put("/{product_id}", response_model=ProductRead) +@router.put("/{product_id}", response_model=ProductUpdate) def update_product( product_id: int, - name: str = Form(None), - description: str = Form(None), - price: float = Form(None), - stock: int = Form(None), - category_id: int = Form(None), - file: UploadFile = File(None), + name: str = Form(...), + description: str = Form(...), + price: float = Form(...), + stock: int = Form(...), + category_id: int = Form(...), + images: list[UploadFile] = File(...), session: Session = Depends(get_session), ): product = session.get(Product, product_id) if not product: raise HTTPException(status_code=404, detail="Product not found") - - if name: - product.name = name - if description: - product.description = description - if price is not None: - product.price = price - if stock is not None: - product.stock = stock - if category_id is not None: - product.category_id = category_id + + # if name: + # product.name = name + # if description: + # product.description = description + # if price is not None: + # product.price = price + # if stock is not None: + # product.stock = stock + # if category_id is not None: + # product.category_id = category_id session.add(product) session.commit() session.refresh(product) - if file and file.filename: - file_location = os.path.join(static_dir, f"product_{product.id}_{file.filename}") - with open(file_location, "wb") as buffer: - shutil.copyfileobj(file.file, buffer) - - image = ProductImage(product_id=product.id, image_url=file_location) - session.add(image) - session.commit() + # Get the shop to create the correct directory + shop = session.get(Shop, product.shop_id) + if not shop: + raise HTTPException(status_code=404, detail="Shop not found") + + shop_dir = os.path.join(settings.static_dir, f"shop_{shop.name}") + os.makedirs(shop_dir, exist_ok=True) + + product_dir = os.path.join(shop_dir, f"product_{product.name}") + os.makedirs(product_dir, exist_ok=True) + + if images: + for file in images: + if file.filename: + file_location = os.path.join(product_dir, file.filename) + with open(file_location, "wb") as buffer: + shutil.copyfileobj(file.file, buffer) + + image = ProductImage(product_id=product.id, image_url=file_location) + session.add(image) + session.commit() return product @@ -119,41 +150,3 @@ def delete_product(product_id: int, session: Session = Depends(get_session)): session.delete(product) session.commit() return {"message": "Product deleted successfully"} - - -@router.post("/ProductImage/", response_model=ProductImageRead) -def upload_product_image( - product_id: int = Form(...), - file: UploadFile = File(...), - session: Session = Depends(get_session), -): - product = session.get(Product, product_id) - if not product: - raise HTTPException(status_code=404, detail="Product not found") - - file_location = os.path.join(static_dir, f"product_{product.id}_{file.filename}") - with open(file_location, "wb") as buffer: - shutil.copyfileobj(file.file, buffer) - - image = ProductImage(product_id=product.id, image_url=file_location) - session.add(image) - session.commit() - return image - - -@router.get("/ProductImage/{product_id}", response_model=list[ProductImageRead]) -def get_product_images(product_id: int, session: Session = Depends(get_session)): - images = session.query(ProductImage).filter(ProductImage.product_id == product_id).all() - if not images: - raise HTTPException(status_code=404, detail="No images found for this product") - return images - - -@router.delete("/ProductImage/{image_id}") -def delete_product_image(image_id: int, session: Session = Depends(get_session)): - image = session.get(ProductImage, image_id) - if not image: - raise HTTPException(status_code=404, detail="Image not found") - session.delete(image) - session.commit() - return {"message": "Product image deleted successfully"} diff --git a/app/backend/routes/shop.py b/app/backend/routes/shop.py index 6641eb3..e6f364d 100644 --- a/app/backend/routes/shop.py +++ b/app/backend/routes/shop.py @@ -4,14 +4,12 @@ from backend.models.models import Shop, User from backend.schemas.shop import ShopCreate, ShopRead from backend.database import get_session from backend.routes.auth import get_current_user +from core.config import settings import shutil import os router = APIRouter() -static_dir = os.path.join("app", "static") -os.makedirs(static_dir, exist_ok=True) - @router.post("/", response_model=ShopRead) def create_shop( @@ -19,32 +17,30 @@ def create_shop( description: str = Form(None), file: UploadFile = File(None), session: Session = Depends(get_session), - current_user: User = Depends(get_current_user), - #owner_id = int, - + # current_user: User = Depends(get_current_user), + owner_id=int, ): - shop = ShopCreate(name=name, description=description, owner_id=current_user.id) - #shop = ShopCreate(name=name, description=description, owner_id=owner_id) + # shop = ShopCreate(name=name, description=description, owner_id=current_user.id) + shop = ShopCreate(name=name, description=description, owner_id=owner_id) db_shop = Shop.from_orm(shop) + session.add(db_shop) + session.commit() + session.refresh(db_shop) + + shop_dir = os.path.join(settings.static_dir, f"shop_{db_shop.name}") + os.makedirs(shop_dir, exist_ok=True) + if file and file.filename: - # Save the image to the static directory - file_location = os.path.join(static_dir, f"{db_shop.name}_{file.filename}") + file_location = os.path.join(shop_dir, file.filename) with open(file_location, "wb") as buffer: shutil.copyfileobj(file.file, buffer) - db_shop.image_url = file_location else: - # Set a default image URL if no file is uploaded - db_shop.image_url = os.path.join(static_dir, "default_shop_image.png") + db_shop.image_url = os.path.join( + settings.static_dir, "default/default_shop.png" + ) - session.add(db_shop) - session.commit() - session.refresh(db_shop) - - # if file: - # # Delete the image file after session commit - # os.remove(file_location) return db_shop @@ -79,25 +75,23 @@ def update_shop( if description: db_shop.description = description + shop_dir = os.path.join(settings.static_dir, f"shop_{db_shop.name}") + os.makedirs(shop_dir, exist_ok=True) + if file and file.filename: - # Save the image to the static directory - file_location = os.path.join(static_dir, f"{db_shop.name}_{file.filename}") + file_location = os.path.join(shop_dir, file.filename) with open(file_location, "wb") as buffer: shutil.copyfileobj(file.file, buffer) - db_shop.image_url = file_location else: - # Set a default image URL if no file is uploaded - db_shop.image_url = os.path.join(static_dir, "default_shop_image.png") + db_shop.image_url = os.path.join( + settings.static_dir, "default/default_shop.png" + ) session.add(db_shop) session.commit() session.refresh(db_shop) - if file: - # Delete the image file after session commit - os.remove(file_location) - return db_shop diff --git a/app/core/config.py b/app/core/config.py index 9666c8a..7e46517 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,5 +1,6 @@ from pathlib import Path from pydantic_settings import BaseSettings, SettingsConfigDict +import os class Settings(BaseSettings): @@ -16,6 +17,10 @@ class Settings(BaseSettings): def database_url(self) -> str: return f"mysql+pymysql://{self.database_username}:{self.database_password}@{self.database_host}/{self.database_name}" + @property + def static_dir(self) -> str: + return os.path.join("app", "static") + model_config = SettingsConfigDict( env_file=str(Path(__file__).resolve().parent.parent / ".env"), env_file_encoding="utf-8", diff --git a/app/static/default/default_product.png b/app/static/default/default_product.png new file mode 100644 index 0000000000000000000000000000000000000000..f8a26b2d08887153a17797e6762ee17d71a89d08 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0y~yU@!t<4mJh`208nVjSLJ7oCO|{#S9GG!XV7ZFl&wk z0|TS8r;B4q#hkY@482$!1zhK6ta!m0V{%toqLMe*@QZ+OUe*gu7U9TpW%J7iiaFe* zIwYp>d~s4Xvc0?aT-{c=5Tnr8;Q9COIyOJHSp9&Zf+gp{4tBoqMGO{9^R6iza<XAQ zzE#PuVf%#wt~a7zBKW49<|~lBwvTx^tL+VjSs5MP39FX`woaJln;`Uc2gm)Yjl40f zt?~yfORsQ57Kz1V{=UPo`^$sG-scCa+^my@eybXu2>aoArnMvSod=t8f?Vv>`>wNR zGydkVHafqfG;eC_p0=%z`(_ocs0<V{`mNp9bEsjZu~DeKvU7r-3s1585rc9#6<oZ8 zGe2ynWw4Nt{Xbu$q9CV7j{EuUlsrk<9(KKcjX`)=L?`z_*^7rlWLDO0FcVj5TWJy0 t{Wn@sP0mw{$vH~t-6bQL<BE@j?bp6~_<#DFZUzPh22WQ%mvv4FO#p73nezYu literal 0 HcmV?d00001 diff --git a/app/static/default/default_shop.png b/app/static/default/default_shop.png new file mode 100644 index 0000000000000000000000000000000000000000..ed0ec74950384a12f8f40a8e3bba9d1247c4c562 GIT binary patch literal 633 zcmeAS@N?(olHy`uVBq!ia0y~yU@!t<4mJh`208nVjSLJ7oCO|{#S9GG!XV7ZFl&wk z0|S$`r;B4q#hkY@4*H2W3bfffFOrE67S2D!yrN*rkp=pWj|3h2Cloj>Qm<vybDQV5 zSzYJ=b5UEtwO;pDUK!Ryo-<N>)VHQx3j1EduYFtbuX^dtm8*XKU-@r&wV08Skx|3# z16l<vQ<%GyA246ob;iYxKfodLs93?`&W?7@3Hoby+;=%q!gR!2n`e23jdw#uX6r){ z*3Dwqr?`FgdZ(?r{_V@VVV`{YrMbQCrLFNdDQZ8kVbboK?26J}_jDJmexldfHG`#& z-7lHL;$`!M;FqFCQ@Inmr0y`*x%ebs+Bhw_bw-7V;Z)`ad294zE*nI=TP$!^ecj56 zzl(k@T7J()lIicokd9}<&9e{qyPvhMlVm?9d$L<DXupi9yshbc8PjFcxx4#j6+iqZ z&M(thx;yiD;OA?>pU(w;z8frj)IVD7^$)}66`Q`>m@YoBG3fiIXK@GrL=~N~nNq>u zbH(I+=TEiu7j&zy@cA&rHyF=6(%mpC%(+g|^O4~PDT&Q>=CdEK(dkS)%ADVz?zMk; zQEte~^s2L3e~+~^KNRZCy=h;yOzR16>Y1(Tbt~lbzdea^FRH%2>r(dZTMPB2zTKW4 zcThvPKY?df#?01;9p8j+PCb8iSH#CJ5u9%}{<d%Z;kR|+{of1k-+imIq{&9mF)m6p zr9Wh%t<nj(om%}RPuWU0PX5&v@lA1)fRxV?j|wH%o(X=3oc0~#nCTsH!l!4#EBSm^ nCMT|kpKQWh+}w_t9+r=fepmi$on96L0|SGntDnm{r-UW|0E`xx literal 0 HcmV?d00001 -- GitLab