In Django the ORM is already a repository, so I do not wrap every query.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # ====================================================================== # Q: Repository pattern and dependency injection: do you need them in Django? # # In Django the ORM is already a repository, so I do not wrap every query. I do # keep ports for external dependencies, because that is where the real value is. # In FastAPI/SQLAlchemy the repository is more natural. # Protocol gives structural typing: the fake does not need to inherit from # anything, and mypy checks that it matches. # ====================================================================== from typing import Protocol class ErpClient(Protocol): def push_order(self, order_id: int, payload: dict) -> str: ... class HttpErpClient: def __init__(self, session: httpx.Client, base_url: str): self._s, self._url = session, base_url def push_order(self, order_id, payload): r = self._s.post(f'{self._url}/orders', json=payload, headers={'Idempotency-Key': f'order-{order_id}'}, timeout=10) r.raise_for_status() return r.json()['erp_ref'] class FakeErpClient: # for tests def __init__(self): self.sent = [] def push_order(self, order_id, payload): self.sent.append((order_id, payload)); return 'ERP-1' def sync_order(order: Order, erp: ErpClient) -> None: # injected order.external_ref = erp.push_order(order.id, serialize(order)) order.save(update_fields=['external_ref']) |