fix model
swadhinbiswas committed 2 years ago
8d37f99
1 parent 9faafe7
commit 8d37f99
10 files changed
+301 -63
Showing 10 changed files+301-63
▼backend/api/v1/handelars/handelars.py
+64-0
| @@ -0,0 +1,64 @@ | ||
1 | +from model.imagemodel import ImageModel | |
2 | +from schemas.imageschema import ImageBase,ImageOut,Update | |
3 | +from services.imageservice import ImageService | |
4 | +from fastapi import APIRouter, HTTPException | |
5 | +from typing import List, Optional | |
6 | +from fastapi import FastAPI | |
7 | +from fastapi.responses import HTMLResponse | |
8 | +from fastapi import File, UploadFile | |
9 | + | |
10 | +router = APIRouter() | |
11 | + | |
12 | +@router.post("/api/v1/images", summary="creatimage",response_model=ImageOut) | |
13 | +async def createimage(image: ImageModel): | |
14 | + await ImageService.create_image(image) | |
15 | + return image | |
16 | + | |
17 | +@router.get("/api/v1/images/{imagename}", response_model=ImageOut) | |
18 | +async def get_image(imagename: str): | |
19 | + image = await ImageService.get_by_imagename(imagename) | |
20 | + if image is None: | |
21 | + raise HTTPException(status_code=404, detail="Image not found") | |
22 | + return image | |
23 | + | |
24 | +@router.put("/api/v1/images/{imagename}", response_model=ImageModel) | |
25 | +async def update_image(imagename: str, update: Update): | |
26 | + image = await ImageService.update_image(imagename, update) | |
27 | + if image is None: | |
28 | + raise HTTPException(status_code=404, detail="Image not found") | |
29 | + return image | |
30 | + | |
31 | +@router.delete("/api/v1/images/{imagename}", response_model=ImageOut) | |
32 | +async def delete_image(imagename: str): | |
33 | + image = await ImageService.delete_image(imagename) | |
34 | + if image is None: | |
35 | + raise HTTPException(status_code=404, detail="Image not found") | |
36 | + return image | |
37 | + | |
38 | +@router.get("/api/v1/images", response_model=List[ImageOut]) | |
39 | +async def get_all_images(): | |
40 | + return await ImageService.get_all_images() | |
41 | + | |
42 | +@router.get("/api/v1/images/tags/{tag}", response_model=List[ImageOut]) | |
43 | +async def get_images_by_tag(tag: str): | |
44 | + return await ImageService.get_images_by_tag(tag) | |
45 | + | |
46 | +@router.get("/api/v1/images/tags", response_model=List[ImageOut]) | |
47 | +async def get_images_by_tags(tags: List[str]): | |
48 | + return await ImageService.get_images_by_tags(tags) | |
49 | + | |
50 | +@router.get("/api/v1/images/many", response_model=List[ImageOut]) | |
51 | +async def get_many(limit: int, skip: int): | |
52 | + return await ImageService.get_many(limit, skip) | |
53 | + | |
54 | +@router.get("/api/v1/images/search", response_model=List[ImageOut]) | |
55 | +async def get_by_search(search: str): | |
56 | + return await ImageService.get_by_search(search) | |
57 | + | |
58 | +@router.get("/api/v1/images/random", response_model=List[ImageOut]) | |
59 | +async def select_random(): | |
60 | + return await ImageService.select_random() | |
61 | + | |
62 | +@router.get("/api/v1/images/random/many", response_model=List[ImageOut]) | |
63 | +async def select_random_many(limit: int): | |
64 | + return await ImageService.select_random_many(limit) | |
0 | 65 | |
▼backend/app.py
+59-0
| @@ -0,0 +1,59 @@ | ||
1 | +from fastapi import FastAPI | |
2 | +from fastapi.middleware.cors import CORSMiddleware | |
3 | +from fastapi.responses import JSONResponse | |
4 | +from fastapi.exceptions import RequestValidationError | |
5 | +from pydantic import ValidationError | |
6 | +from starlette.exceptions import HTTPException | |
7 | +from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY | |
8 | +from typing import List | |
9 | +from model.usemodel import UseModel | |
10 | +from model.imagemodel import ImageModel | |
11 | +from schemas.imageschema import ImageBase,ImageOut,Update | |
12 | +from api.v1.handelars.handelars import router | |
13 | +from beanie import init_beanie, Document | |
14 | +from motor.motor_asyncio import AsyncIOMotorClient | |
15 | +from contextlib import asynccontextmanager | |
16 | + | |
17 | + | |
18 | +async def init(): | |
19 | + client = AsyncIOMotorClient( | |
20 | + "mongodb+srv://test1:[email protected]/?retryWrites=true&w=majority&appName=testbatch" | |
21 | + ) | |
22 | + | |
23 | + await init_beanie(database=client.test, document_models=[ImageModel]) | |
24 | + | |
25 | + | |
26 | +@asynccontextmanager | |
27 | +async def lifespan(app: FastAPI): | |
28 | + await init() | |
29 | + try: | |
30 | + yield | |
31 | + finally: | |
32 | + pass | |
33 | + | |
34 | + | |
35 | + | |
36 | +app = FastAPI(lifespan=lifespan) | |
37 | + | |
38 | +app.add_middleware( | |
39 | + CORSMiddleware, | |
40 | + allow_origins=["*"], | |
41 | + allow_credentials=True, | |
42 | + allow_methods=["*"], | |
43 | + allow_headers=["*"], | |
44 | +) | |
45 | + | |
46 | + | |
47 | + | |
48 | +app.include_router(router,prefix="/api/v1") | |
49 | + | |
50 | + | |
51 | + | |
52 | + | |
53 | + | |
54 | + | |
55 | + | |
56 | +if __name__ == "__main__": | |
57 | + import uvicorn | |
58 | + uvicorn.run(app,host="localhost",port=8000) | |
59 | + | |
0 | 60 | |
▼backend/db/dbconnector.py
+1-0
| @@ -0,0 +1 @@ | ||
1 | + | |
0 | 2 | |
▼backend/html/imageslider.py
+20-0
| @@ -0,0 +1,20 @@ | ||
1 | +from fastapi import APIRouter | |
2 | +from fastapi import FastAPI | |
3 | +from fastapi.responses import HTMLResponse | |
4 | + | |
5 | +router = FastAPI() | |
6 | + | |
7 | + | |
8 | + | |
9 | +@router.get("/html/elements/imageslider", responses={200: {"content": {"text/html": {}}}}) | |
10 | +async def get_html_imageslider(): | |
11 | + | |
12 | + | |
13 | + | |
14 | + return HTMLResponse( | |
15 | + ) | |
16 | + | |
17 | + | |
18 | +if __name__ == "__main__": | |
19 | + import uvicorn | |
20 | + uvicorn.run(router, host="localhost", port=8000) | |
0 | 21 | |
▼backend/model/imagemodel.py
+35-54
| @@ -1,78 +1,59 @@ | ||
1 | 1 | from beanie import Document,Indexed |
2 | -from typing import List,Any,Final | |
2 | +from typing import Coroutine, List,Any,Final | |
3 | 3 | from datetime import datetime |
4 | +from uuid import UUID,uuid4 | |
5 | +from pydantic import Field | |
6 | + | |
7 | +from pymongo.client_session import ClientSession | |
4 | 8 | |
5 | 9 | class ImageModel(Document): |
6 | - image_id: str=Indexed() | |
10 | + image_id:UUID = Field(default_factory=uuid4) | |
7 | 11 | name: str |
8 | 12 | description: str |
9 | 13 | tags: List[str] |
10 | - created_at: datetime | |
11 | - updated_at: datetime | |
12 | 14 | image_path: str |
13 | 15 | thumbnail_path: str |
14 | - | |
16 | + created_at: datetime=Field(default_factory=datetime.now) | |
17 | + updated_at: datetime=Field(default_factory=datetime.now) | |
18 | + | |
15 | 19 | def __repr__(self) -> str: |
16 | - return f"ImageModel(name={self.name},description={self.description},tags={self.tags},created_at={self.created_at},updated_at={self.updated_at},image_path={self.image_path},thumbnail_path={self.thumbnail_path})" | |
20 | + return f"<ImageModel {self.tags}>" | |
17 | 21 | |
18 | 22 | def __str__(self) -> str: |
19 | - return self.__repr__() | |
20 | - | |
23 | + return f"<ImageModel {self.tags}>" | |
21 | 24 | def __eq__(self, o: object) -> bool: |
22 | - if not isinstance(o,ImageModel): | |
25 | + if not isinstance(o, ImageModel): | |
23 | 26 | return False |
24 | - return self.name == o.name and self.description == o.description and self.tags == o.tags and self.created_at == o.created_at and self.updated_at == o.updated_at and self.image_path == o.image_path and self.thumbnail_path == o.thumbnail_path | |
25 | - | |
26 | - def __ne__(self, o: object) -> bool: | |
27 | - return not self.__eq__(o) | |
28 | - | |
29 | - @property | |
30 | - def id(self) -> Any: | |
31 | - return self._id | |
32 | - | |
33 | - @property | |
34 | - def name(self) -> str: | |
35 | - return self._name | |
36 | - | |
37 | - @property | |
38 | - def description(self) -> str: | |
39 | - return self._description | |
27 | + return self.image_id==o.image_id | |
40 | 28 | |
41 | - @property | |
42 | - def tags(self) -> List[str]: | |
43 | - return self._tags | |
29 | + def __hash__(self) -> int: | |
30 | + return hash(self.image_id) | |
44 | 31 | |
45 | 32 | @property |
46 | - def created_at(self) -> datetime: | |
47 | - return self._created_at | |
33 | + def create(self)->datetime: | |
34 | + return self.created_at | |
48 | 35 | |
49 | - @property | |
50 | - def updated_at(self) -> datetime: | |
51 | - return self._updated_at | |
36 | + @classmethod | |
37 | + async def getbytags(cls,tags:List[str],session:ClientSession): | |
38 | + return await cls.find({"tags":{"$in":tags}}).to_list() | |
39 | + | |
52 | 40 | |
53 | - @property | |
54 | - def image_path(self) -> str: | |
55 | - return self._image_path | |
41 | + | |
56 | 42 | |
57 | - @property | |
58 | - def thumbnail_path(self) -> str: | |
59 | - return self._thumbnail_path | |
43 | + class Settings: | |
44 | + name="imagemodel" | |
60 | 45 | |
61 | - @id.setter | |
62 | - def id(self, value: Any): | |
63 | - self._id = value | |
46 | + class Config: | |
64 | 47 | |
65 | - @name.setter | |
66 | - def name(self, value: str): | |
67 | - self._name = value | |
48 | + json_schema_extra={ | |
49 | + "example":{ | |
50 | + "name":"image", | |
51 | + "description":"This is an image", | |
52 | + "tags":["image","tag"], | |
53 | + "image_path":"https://path/to/image", | |
54 | + "thumbnail_path":"https://path/to/image/thumbnail", | |
55 | + "created_at":datetime.now(), | |
56 | + } | |
57 | + } | |
68 | 58 | |
69 | - @classmethod | |
70 | - async def get_by_title(cls, name:str ): | |
71 | - return await cls.get_one({"name":name}) | |
72 | - @classmethod | |
73 | - async def get_by_tages(cls, tags:List[str]): | |
74 | - return await cls.get_many({"tags":tags}) | |
75 | - | |
76 | - class Collection: | |
77 | - name="imagemodel" | |
78 | 59 | |
79 | 60 | |
▼backend/model/tagmodel.py
+1-1
| @@ -24,6 +24,6 @@ class TagModel(Document): | ||
24 | 24 | return self._name |
25 | 25 | |
26 | 26 | |
27 | - class Collection: | |
27 | + class Settings: | |
28 | 28 | name="tagmodel" |
29 | 29 | |
30 | 30 | |
▼backend/model/usemodel.py
+1-1
| @@ -42,7 +42,7 @@ class UseModel(Document): | ||
42 | 42 | async def get_user_by_username(cls,username:str,session:ClientSession)->Optional['UseModel']: |
43 | 43 | return await cls.get_one({"username":username},session=session) |
44 | 44 | |
45 | - class Collection: | |
45 | + class Settings: | |
46 | 46 | name="usermodel" |
47 | 47 | |
48 | 48 | |
49 | 49 | |
▼backend/schemas/imageschema.py
+3-0
| @@ -7,6 +7,9 @@ class ImageBase(BaseModel): | ||
7 | 7 | tags:List[str]=Field([],description="List of tags") |
8 | 8 | image_path:str=Field(...,description="Path to the image") |
9 | 9 | thumbnail_path:str=Field(...,description="Path to the thumbnail") |
10 | + | |
11 | + | |
12 | + | |
10 | 13 | |
11 | 14 | class ImageOut(BaseModel): |
12 | 15 | name:str |
13 | 16 | |
▼backend/services/imageservice.py
+20-7
| @@ -1,20 +1,25 @@ | ||
1 | 1 | import pymongo |
2 | 2 | from typing import Optional,List |
3 | +from datetime import datetime | |
3 | 4 | from uuid import UUID, uuid4 |
4 | 5 | from schemas.imageschema import ImageBase,ImageOut,Update |
5 | 6 | from model.imagemodel import ImageModel |
6 | 7 | |
7 | 8 | class ImageService: |
8 | 9 | @staticmethod |
9 | - async def create_image(image:ImageBase): | |
10 | - image_in=ImageModel( | |
11 | - imagename=image.imagename, | |
12 | - imagedescription=image.imagedescription, | |
13 | - imageurl=image.imageurl, | |
10 | + async def create_image(image:ImageBase)->ImageModel: | |
11 | + newimage=ImageModel( | |
12 | + image_id=uuid4(), | |
13 | + name=image.name, | |
14 | + description=image.description, | |
14 | 15 | tags=image.tags, |
16 | + image_path=image.image_path, | |
17 | + thumbnail_path=image.thumbnail_path, | |
18 | + created_at=datetime.now(), | |
19 | + updated_at=datetime.now(), | |
15 | 20 | ) |
16 | - await image_in.save() | |
17 | - return image_in | |
21 | + await newimage.insert() | |
22 | + | |
18 | 23 | @staticmethod |
19 | 24 | async def get_by_imagename(imagename:str)->Optional[ImageModel]: |
20 | 25 | theimage= await ImageModel.find_one(ImageModel.imagename==imagename) |
| @@ -52,3 +57,11 @@ class ImageService: | ||
52 | 57 | async def get_by_search(search:str)->List[ImageModel]: |
53 | 58 | images=await ImageModel.find({"$text":{"$search":search}}).to_list() |
54 | 59 | return images |
60 | + @staticmethod | |
61 | + async def select_random()->List[ImageModel]: | |
62 | + images=await ImageModel.aggregate([{"$sample":{"size":1}}]).to_list() | |
63 | + return images | |
64 | + @staticmethod | |
65 | + async def select_random_many(limit:int)->List[ImageModel]: | |
66 | + images=await ImageModel.aggregate([{"$sample":{"size":limit}}]).to_list() | |
67 | + return images | |
55 | 68 | |
▼teatbine/mainapp.py
+97-0
| @@ -0,0 +1,97 @@ | ||
1 | +from typing import Optional | |
2 | +from fastapi import FastAPI | |
3 | +import motor.motor_asyncio | |
4 | +from motor.motor_asyncio import AsyncIOMotorClient | |
5 | +from pydantic import BaseModel | |
6 | +from mongomock_motor import AsyncMongoMockClient | |
7 | + | |
8 | +from beanie import Document, Indexed, init_beanie | |
9 | + | |
10 | +from pymongo.server_api import ServerApi | |
11 | +uri = "mongodb+srv://test1:[email protected]/?retryWrites=true&w=majority&appName=testbatch" | |
12 | +# Create a new client and connect to the server | |
13 | +client = MongoClient(uri) | |
14 | +# Send a ping to confirm a successful connection | |
15 | + | |
16 | + | |
17 | + | |
18 | +class Category(BaseModel): | |
19 | + name: str | |
20 | + description: str | |
21 | + | |
22 | + | |
23 | + class Meta: | |
24 | + collection = "categories" | |
25 | + | |
26 | + async def insert(self): | |
27 | + await Category.insert_one(self) | |
28 | + | |
29 | + async def update(self): | |
30 | + await Category.update_one(self) | |
31 | + | |
32 | + async def delete(self): | |
33 | + await Category.delete_one(self) | |
34 | + | |
35 | + | |
36 | +# This is the model that will be saved to the database | |
37 | +class Product(Document): | |
38 | + name: str # You can use normal types just like in pydantic | |
39 | + description: Optional[str] = None | |
40 | + price: Indexed(float) # You can also specify that a field should correspond to an index | |
41 | + category: Category | |
42 | + | |
43 | + class Meta: | |
44 | + collection = "products" # Specify the collection name | |
45 | + indexes = [ # Specify the indexes | |
46 | + {"key": [("name", 1)], "unique": True}, | |
47 | + {"key": [("price", 1)]} | |
48 | + ] | |
49 | + class Config: | |
50 | + schema_extra = { | |
51 | + "example": { | |
52 | + "name": "Product Name", | |
53 | + "description": "Product Description", | |
54 | + "price": 100.0, | |
55 | + "category": {"name":"Category Name","description":"Category Description"} | |
56 | + } | |
57 | + } | |
58 | + | |
59 | + async def insert(self): | |
60 | + await Product.insert_one(self) | |
61 | + | |
62 | + | |
63 | + | |
64 | + | |
65 | +# Call this from within your event loop to get beanie setup. | |
66 | +async def init(): | |
67 | + # Create Motor client | |
68 | + client=client | |
69 | + | |
70 | + # Init beanie with the Product document class | |
71 | + await init_beanie(database=client.test, document_models=[Product]) | |
72 | + | |
73 | + | |
74 | +app = FastAPI() | |
75 | + | |
76 | +@app.post("/products/") | |
77 | +async def create_product(product: Product): | |
78 | + await product.insert() | |
79 | + return product.Config() | |
80 | + | |
81 | +@app.get("/products/") | |
82 | +async def get_products(): | |
83 | + products = await Product.find_all().to_list() | |
84 | + return products | |
85 | + | |
86 | +@app.get("/products/{product_id}") | |
87 | +async def get_product(product_id:str): | |
88 | + product = await Product.get(product_id) | |
89 | + return product.Config() | |
90 | + | |
91 | + | |
92 | + | |
93 | +if __name__ == "__main__": | |
94 | + import uvicorn | |
95 | + uvicorn.run(app, host="localhost", port=8000) | |
96 | + | |
97 | + | |
0 | 98 | |