Last active
May 8, 2024 14:20
-
-
Save uris77/4711015 to your computer and use it in GitHub Desktop.
Example of Repository Pattern with SQLAlchemy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a very crud example of using the Repository Pattern with SQLAlchemy. It allows me to completely ignore interactions with | |
# the database. This is only pulled in whenever I require to persist or retrieve an object from the database. The domain/business | |
# logic is entirely separated from persistence and I can have true unit tests for those. | |
# The tests for persistence are then limited to very specific cases of persistence and retrieving instances, and I can do those | |
# independent of the business logic. They also tend to be less tests since I only need to test them once. | |
class Person(object): | |
def __init__(self): | |
# This is entity is mapped to the DB using SQLAlchemy's classical mapping. | |
It also includes an Address | |
pass | |
class Address(object): | |
def __init__(self): | |
pass | |
class PersonRepository(object): | |
def __init__(self, DBSession): | |
self.session = DBSession | |
def persist(self, entity): | |
self.session.add(entity) | |
self.session.flush() | |
return entity | |
class AddressEditor(object): | |
def __init__(self): | |
pass | |
def add_address(self, person, address): | |
person.address = address | |
#We can either inject the session into this method, or | |
#obtain it from a configuration file. | |
repository = PersonRepository(DBSession) | |
person = repository.persist(person) | |
return person.address | |
According to Mike Bayers (creator of SQLAlchemy) Blog - Patterns implemented by SQLAlchemy the Repository Pattern is implemented, in general, with SQLAlchemy Sessions. Are there other variants of this pattern in addition to the example from SQLAlchemy docs (session is "injected" via class method, either explicitly or using an object manager)?
Thank you for your pointer.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi there, your code snippet make sense in this controlled size. I do have a similar modeling. The only challenge I am facing is a python cyclic import issue am facing.
For demonstration purposes, I do have an Sqlalchemy model: Event living inside an event.py module.
Creating a Repository for this model, I end up with an EventRepository living in it's own module named event_repository.
Let's assume my Event module has these exposed behaviours
Event.add_review(Review review)
Event.get_review()
In my controller is where I call my module with the needed behaviour depending on the context of the request action.
Now the issue is, my repository depends on my model Event whereas my EventRepository equally depends on my Event model. This situation leaves me with a python cyclic import issues.
A solution for this is to have SQLAlchemy models act only as persistence tables and nothing more. Meaning rather than tieing my business models to my database table. I create pure models to handle my business logic.
The workload here is mapping/hydrating my pure models with the data retrieved by the EventRepository.
I wonder if there is an alternative solution that I can't seem to see at the moment.
A word or two on this would he greatly appreciated.