SeoulNative / naengboo

naengboo backend repo
2 stars 2 forks source link

pymongo 사용 방법 논의(dao) #12

Open hoyeon94 opened 3 years ago

hoyeon94 commented 3 years ago

What

Description

Related

livlikwav commented 3 years ago

디렉터리 구조가 아니라, 디렉터리 구조 뿐만 아니라 DAO나 DTO 같은 걸 어떻게 만들고, 어떤식으로 쿼리 코드를 작성하는지 알아봐야할 듯 합니다. ORM 기술을 사용하지 않을 때의 Best practice를 찾아봅시다.

coloryourlife commented 3 years ago

https://github.com/akmamun/mvc-flask-pymongo

hoyeon94 commented 3 years ago

제홍님께서 올려주신 https://github.com/akmamun/mvc-flask-pymongo 참고하여 pseudo code로 짜봤습니다.

daos/base_dao.py

from datetime import datetime
from bson import ObjectId
from app import db

class BaseDao(object):
    def __init__(self, collection_name):
        self.db = db
        self.collection_name = collection_name

    def insert(self, element):
        element["created"] = datetime.now()
        element["updÍated"] = datetime.now()
        inserted = self.db[self.collection_name].insert_one(element)  # insert data to db
        return str(inserted.inserted_id)

    def find(self, criteria, projection=None, sort=None, limit=0, cursor=False):  # find all from db

        if "_id" in criteria:
            criteria["_id"] = ObjectId(criteria["_id"])

        found = self.db[self.collection_name].find(filter=criteria, projection=projection, limit=limit, sort=sort)

        if cursor:
            return found

        found = list(found)

        for i in range(len(found)):  # to serialize object id need to convert string
            if "_id" in found[i]:
                found[i]["_id"] = str(found[i]["_id"])

        return found

    def find_by_id(self, id):
        found = self.db[self.collection_name].find_one({"_id": ObjectId(id)})

        if found is None:
            return not found

        if "_id" in found:
             found["_id"] = str(found["_id"])

        return found

    def update(self, id, element):
        criteria = {"_id": ObjectId(id)}

        element["updated"] = datetime.now()
        set_obj = {"$set": element}  # update value

        updated = self.db[self.collection_name].update_one(criteria, set_obj)
        if updated.matched_count == 1:
            return "Record Successfully Updated"

    def delete(self, id):
        deleted = self.db[self.collection_name].delete_one({"_id": ObjectId(id)})
        return bool(deleted.deleted_count)

daos/ingredients_dao.py

from app.daos.base_dao import BaseDao

class IngredientsDao(BaseDao):
    def __init__(self):
        BaseDao.__init__(self, "Ingredients")

    def get_user_ingredients(self, user_id):
        self.find(criteria={
            "user_id": user_id
        })

views/refrigerators.py

from flask_restx import Namespace, Resource
from flask import jsonify
from bson.json_util import dumps
from app import db
from daos.ingredients_dao import IngredientsDao

ingredients_dao = IngredientsDao

Refrigerators = Namespace(
    name="Refrigerators",
    description="APIs for refrigerators"
)

@Refrigerators.route('/ingredients')
class Ingredients(Resource):
    def getUserIngredients(self):
        request_user_id = request.parsing("user_id")
        ingredients_dao.get_user_ingredients(request_user_id)
        return jsonify(get_user_ingredients)
hoyeon94 commented 3 years ago

위에 올린 코드를 간략하게 설명하자면, daos/base_dao.BaseDao를 상위클래스로, 각 collection들에 대한 dao들(예를 들어 IngredientsDao 등)을 BaseDao하위클래스로 둡니다. 공통으로 사용하는 db 접근 함수들은 BaseDao에 구현함으로써 중복되는 코드를 최소화하려고 했습니다!

일단 아래와 같이 BaseDao에 crud와 관련된 함수들을 구현하도록 하겠습니다!

혹시 더 추가하면 좋겠다 싶은 것들은 comment로 남겨주세요!

livlikwav commented 3 years ago

DAO 이대로 빠르게 가셔도 좋을 것 같습니다~

hoyeon94 commented 3 years ago

아래와 같이 dao를 사용하면 좋을 것 같습니다. 확인 부탁드립니다!

구조

base_dao.py

class IngredientsDao(BaseDao): def init(self): BaseDao.init(self, "ingredients")

def example_get_all_ingredients(self):
    return self.find_list_by_filter({}) # (O) BaseDao에 구현된 find_list_by_filter 함수를 이용해 db 접근
    return self.__db.find({filter{...}) # (X) 어차피 이렇게 할 수도 없습니다!
2. typehint를 써 주세요!
```python
def find_one_by_id(self, id:str)-> object:
    found = self.__db[self.collection_name].find_one({"_id": ObjectId(id)})

    if found:
        found["_id"] = str(found["_id"])

    return found

Related

Init daos pull request

coloryourlife commented 3 years ago

모듈 이름 수정 건의해봅니다. base_dao는 현재의 측면에서만 놓고 보았을 때, dao의 기능보다는 pymongo의 api 함수들을 호출하여 한번 더 우리가 편한 이름으로 wrapping해서 쓰이고 있는 개념인지라, base_dao가 아닌 다른 이름을 사용하는게 더 적합하지 않을까 싶습니다.

do168 commented 3 years ago

지난 회의에서 dao 로 용어를 굳히기로 했던 것 아니었나요?. 혹시 변경사항이 있나요?

coloryourlife commented 3 years ago

지난 회의에서 dao 로 용어를 굳히기로 했던 것 아니었나요?. 혹시 변경사항이 있나요?

다른 recipe_dao 이런 것들 말고 base_dao만 얘기하는겁니다! 실질적으로 데이터베이스에 접근하는 코드는 다른 dao에서 작성되고 base_dao에서는 데이터베이스에 접근하는 pymongo 함수와 mapping해주기만 하는 것 같아서요!

hoyeon94 commented 3 years ago

저는 클래스의 기능? 보다는 역할에 초점을 맞춰서 이렇게 네이밍 했습니다,, 떠도는 예제들을 보면 여러개의 클래스가 모두 상속받는 클래스를 base*** 이런식으로 많이 하더라구요,, 혹시 제홍님께서 생각하는 다른 클래스 이름이 있으신가여?