FastAPI — beanie — MongoDB
Description du couplage entre le service web et la base de données :
Lien vers la documentation de beanie :
Développement du module de database avec les interfaces dédiées pour les différentes opérations souhaitées de manipulation des données dans le cadre du projet de rétrosynthèse. dans ce projet on souhaite stocker dans un système MongoDB deux types de données, les informations sur la rétrosynthèse (le smile, date, la référence interne et nb_routes) et les commentaires sur chaque solution trouvée (date, texte du commentaire). Ces différentes informations seront stockées dans une collection dédiée : retrosyntheses et comments. Donc les opérations à réaliser couvrent les aspects classiques d’un CRUD.
Exemple de module database : CRUD
from beanie import init_beanie, PydanticObjectId
from beanie.operators import In, RegEx
from motor.motor_asyncio import AsyncIOMotorClient
from pydantic import BaseModel
from pydantic_settings import BaseSettings
from typing import Any, List, Optional
from models.retrosynthese import Retrosynthese
from models.comments import CommentDoc
class Settings(BaseSettings):
DATABASE_URL: Optional[str] = None
SECRET_KEY: Optional[str] = None
async def initialize_database(self):
client = AsyncIOMotorClient(self.DATABASE_URL)
await init_beanie(
database=client.get_default_database(),document_models=[Retrosynthese, CommentDoc])
class Config:
env_file = ".env"
class Database:
def __init__(self, model):
self.model = model
async def save(self, document) -> None:
await document.create()
return
async def get(self, id: PydanticObjectId) -> Any:
doc = await self.model.get(id)
if doc:
return doc
return False
async def getOne(self, id:str )->Any:
docs = await self.model.find_one(self.model.identifiant == id)
return docs
async def getOneSmile(self, smile:str )->Any:
docs = await self.model.find_one(self.model.smile == smile)
return docs
async def get_allF(self, filtre: str) -> List[Any]:
docs = await self.model.find(RegEx(self.model.identifiant,filtre)).to_list()
return docs
async def get_all(self) -> List[Any]:
docs = await self.model.find_all().to_list()
return docs
async def update(self, id: PydanticObjectId, body: BaseModel) -> Any:
doc_id = id
des_body = body.dict()
des_body = {k:v for k,v in des_body.items() if v is not None}
update_query = {"$set": {
field: value for field, value in
des_body.items()
}}
doc = await self.get(doc_id)
if not doc:
return False
await doc.update(update_query)
return doc
async def delete(self, id: PydanticObjectId) -> bool:
doc = await self.get(id)
if not doc:
return False
await doc.delete()
return True
Explications : il est important pour des manipulations classiques d’insérer beanie.operator qui nous permettra d’accéder à des fonctions spécifiques pour la mise en place de filtre. Dans cette classe, on a mis en place la généricité des modèles utilisés dans le projet. Ce qui permet d’avoir les mêmes fonctions pour les différents modèles.
Explications de la partie initialize de la database :
async def initialize_database(self):
client = AsyncIOMotorClient(self.DATABASE_URL)
await init_beanie(
database=client.get_default_database(),
document_models=[Retrosynthese, CommentDoc])
Dans l’initialisation de la database, on précise les modèles de données que l’on souhaite manipuler. Ce qui dans le code sera définie par l’instruction suivante :
- retro_database=Database(Retrosynthese) # permet d’ouvrir un descripteur sur la collection retrosynthese
- comments_database=Database(CommentDoc) # permet d’ouvrir un descripteur sur la collection CommenDoc
Voir les modèles
class Retrosynthese(Document):
identifiant: str
date: datetime
smile: str
nbroutes: int
class Settings:
name="retrosynthese"
class Config:
json_schema_extra = {
"example": {
"identifiant": "74017a01-ffdb-42fe-80ba-ad77f2fe2750",
"date":"01/01/2026",
"smile": "O=C(O)N1Cc2ccc(-c3cnc4cnccn34)cc2C1",
"nbroutes": 0
}
}
class CommentDoc(Document):
identifiant: str
date: datetime
texte: str
class Settings:
name="comments"
class Config:
json_schema_extra = {
"example": {
"identifiant": "74017a01-ffdb-42fe-80ba-ad77f2fe2750_001",
"date":datetime.now(),
"texte": "commentaires ",
}
}
Explications des méthodes associées à cette classe database et l’utilisation des opérateurs : l’attribut Settings de la classe du modèle permet d’indiquer la collection ciblée qui va contenir les données.
Exemple de mise en place d’agrégation