1. ODM

관계형 DB(RDBMS)가 아닌 NOSQL(NOT ONLY SQL)계열에서 사용하는 ORM이라고 생각하면 된다. 그렇다면 ORM이 무엇일까?

2. ORM

객체 지향 언어가 실용화 된지가 오래이다. 객체 지향언어는 기본적으로 모든 데이터가 객체를 기반으로 작동한다.

그 객체는 일시적이기 때문에, 객체를 오래 저장하고 다음에도 사용하기 위해서 '데이터 베이스'가 생겼다.

만약 RDBMS라면 SQL쿼리를 사용하여 객체의 RETRIEVE, STORE, UPDATE를 수행한다. 즉, 개발자가 저장하고 싶은 객체를 기반으로 SQL쿼리 문을 만들어서(EX : insert into student values(25, 'navin', 'java') 데이터 베이스에 요청하여야했다.

하지만 만약에 어떤 마법사가 객체만을 보고 SQL쿼리 문을 만들어 준다면? 그것이 ORM이다.

대표적인 ORM의 예로, .NET의 경우 ENTITY FRAMEWORK, DJANGO의 경우에도 자체 ORM TOOL이 존재한다.

3. ODM, ORM의 장단점

  • 장점으로는 개발자의 객체지향적, 직관적인 코드로 데이터 베이스를 구성할 수있지만
  • 단점으로 어떤 툴이 개입을 하는 과정이 추가 되기 때문에 속도는 더 오래 걸릴 수있다.

4. beanie를 활용한 간단한 fastapi 앱

1. pipenv로 가상환경 구축

2. requirements.txt -> pip install -r requirements.txt

beanie==1.11.0
fastapi==0.78.0
uvicorn==0.17.6

3. 파일구조

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

4. 구축

  • app/main.py에
import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

uvicorn 서버에 포트 8000으로 작동하게 했고 reload= True를 통해 수정할때마다 reload 되게 했다.

  • app/server/app.py에
from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root() -> dict:
    return {"message": "Welcome to your beanie powered app!"}

추가한 후에 python app/main.py를 통해 실행,
http://localhost:8000로 접속하면

{"message": "Welcome to your beanie powered app!"}

여기까지가 가장 기본적인 fastapi와 Uvicorn을 이용한 웹 서버이다.

  • 이제 db와 api들을 추가해준다.

먼저 db를 연결하기 위해서 스키마 구조부터 짜준다.

from datetime import datetime

from beanie import Document
from pydantic import BaseModel
from typing import Optional


class ProductReview(Document):
    name: str
    product: str
    rating: float
    review: str
    date: datetime = datetime.now()

    class Settings:
        name = "product_review"

    class Config:
        schema_extra = {
            "example": {
                "name": "Abdulazeez",
                "product": "TestDriven TDD Course",
                "rating": 4.9,
                "review": "Excellent course!",
                "date": datetime.now()
            }
        }

class UpdateProductReview(BaseModel):
    name: Optional[str]
    product: Optional[str]
    rating: Optional[float]
    review: Optional[str]
    date: Optional[datetime]

    class Config:
        schema_extra = {
            "example": {
                "name": "Abdulazeez Abdulazeez",
                "product": "TestDriven TDD Course",
                "rating": 5.0,
                "review": "Excellent course!",
                "date": datetime.now()
            }
        }
  1. 우리는 beanie를 이용할거기 때문에 pydantic의 BaseModel이 아니라 beanie의 document를 include한 후 그것을 상속하는 스키마 클래스를 짜준다. (beanie의 document 또한 BaseModel로 구동되기 때문에 (powered by) Swagger docs(api test해주는 기능인거 같음) 에서 example data를 제공할 수 있다고 함.)

  2. 그냥 document를 상속 받기만 하면 database collection과 연결되지 않는다. Settings 라는 sub class를 선언해준다.

  3. Swagger docs에서 example schema를 제공하기 위해
    Config 클래스를 선언한후 schema_extra변수를 선언해준다.

  1. 업데이트를 하기 위한 스키마 구조인 UpdateProductReview클래스는
    BaseModel을 상속받게 한다.(왜?? 요청본문에 있는 필드만 변경하기 위해서라는데... Document를 상속받는 모델은 두개이면 안되는 건가?)

5. mongo db 연결

from beanie import init_beanie
import motor.motor_asyncio

from app.server.models.product_review import ProductReview


async def init_db():
    client = motor.motor_asyncio.AsyncIOMotorClient(
        "mongodb://localhost:27017/productreviews"
    )

    await init_beanie(database=client.db_name, document_models=[ProductReview])

init_db()안에서 client를 설정해준후, init_beanie method를 통해 연결해준다.

main에

@app.on_event("startup")
async def start_db():
    await init_db()

추가하여 startup 시 바로 실행 되도록 했다.

참고 :

profile
computer science engineering

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN