Open hoyeon94 opened 3 years ago
디렉터리 구조가 아니라, 디렉터리 구조 뿐만 아니라 DAO나 DTO 같은 걸 어떻게 만들고, 어떤식으로 쿼리 코드를 작성하는지 알아봐야할 듯 합니다. ORM 기술을 사용하지 않을 때의 Best practice를 찾아봅시다.
제홍님께서 올려주신 https://github.com/akmamun/mvc-flask-pymongo 참고하여 pseudo code로 짜봤습니다.
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)
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
})
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)
위에 올린 코드를 간략하게 설명하자면, daos/base_dao.BaseDao를 상위클래스로, 각 collection들에 대한 dao들(예를 들어 IngredientsDao 등)을 BaseDao하위클래스로 둡니다. 공통으로 사용하는 db 접근 함수들은 BaseDao에 구현함으로써 중복되는 코드를 최소화하려고 했습니다!
일단 아래와 같이 BaseDao에 crud와 관련된 함수들을 구현하도록 하겠습니다!
혹시 더 추가하면 좋겠다 싶은 것들은 comment로 남겨주세요!
DAO 이대로 빠르게 가셔도 좋을 것 같습니다~
아래와 같이 dao를 사용하면 좋을 것 같습니다. 확인 부탁드립니다!
class BaseDao:
def __init__(self, collection_name):
self.__db = db
self.collection_name = collection_name
예시
# app/daos/base_dao.py
class BaseDao:
def __init__(self, collection_name):
self.__db = db
self.collection_name = collection_name
...
def find_list_by_filter(self, filter: dict={}, projection=None, sort=None, skip: int=0, limit: int=0)-> List[dict]:
if "_id" in filter:
filter["_id"] = ObjectId(filter["_id"])
found = self.__db[self.collection_name].find(filter=filter, projection=projection, skip=skip, limit=limit, sort=sort)
found = list(found)
for i in range(len(found)):
if "_id" in found[i]:
found[i]["_id"] = str(found[i]["_id"])
return found
...
# app/daos/ingredients_dao.py
from app.daos.base_dao import BaseDao
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
모듈 이름 수정 건의해봅니다.
base_dao
는 현재의 측면에서만 놓고 보았을 때, dao의 기능보다는 pymongo의 api 함수들을 호출하여 한번 더 우리가 편한 이름으로 wrapping해서 쓰이고 있는 개념인지라, base_dao가 아닌 다른 이름을 사용하는게 더 적합하지 않을까 싶습니다.
지난 회의에서 dao
로 용어를 굳히기로 했던 것 아니었나요?. 혹시 변경사항이 있나요?
지난 회의에서
dao
로 용어를 굳히기로 했던 것 아니었나요?. 혹시 변경사항이 있나요?
다른 recipe_dao
이런 것들 말고 base_dao
만 얘기하는겁니다!
실질적으로 데이터베이스에 접근하는 코드는 다른 dao
에서 작성되고 base_dao
에서는 데이터베이스에 접근하는 pymongo 함수와 mapping해주기만 하는 것 같아서요!
저는 클래스의 기능? 보다는 역할에 초점을 맞춰서 이렇게 네이밍 했습니다,, 떠도는 예제들을 보면 여러개의 클래스가 모두 상속받는 클래스를 base*** 이런식으로 많이 하더라구요,, 혹시 제홍님께서 생각하는 다른 클래스 이름이 있으신가여?
What
Description
Related