Skip to content

Instantly share code, notes, and snippets.

@uris77
Last active September 20, 2023 15:08
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save uris77/4711015 to your computer and use it in GitHub Desktop.
Save uris77/4711015 to your computer and use it in GitHub Desktop.
Example of Repository Pattern with SQLAlchemy
# 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
@fkromer
Copy link

fkromer commented Jan 7, 2018

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)?

@ofelix03
Copy link

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.

@tanduong
Copy link

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