Skip to content

thruflo/pyramid_alchemy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Good frameworks, like Pyramid and Angular, help developers write testable code. SQLAlchemy is a great framework. However, the sheer convenience of having model instances returned from a database query encourages developers to write large ORM classes which can be hard to test.

One way to avoid this is to keep model classes thin and write separate code to instantiate and manipulate them. The downside of this approach is the loss in convenience: the separated, easily testable code isn't provided by default as an attribute of the model instances returned from a database query.

pyramid_alchemy provides an add_model_method Pyramid configuration directive that extends SQLAlchemy ORM classes in the same way that add_request_method extends the Pyramid Request. Using this directive allows developers to write easily testable code that is conveniently available as a model instance attribute. For example, if you include this in your Pyramid application:

from .model import Spam

def get_eggs(instance, source='hens', limit=9, offset=0):
    """Example ORM instance method, implemented as a standalone function."""
    
    query = instance.query.filter_by(source=source)
    return query.offset(offset).limit(limit)

def includeme(config):
    config.add_model_method(Spam, get_eggs, 'get_eggs')

You can then use the get_eggs method from Spam instances:

spam = Session.query(Spam).get(1)
eggs = spam.get_eggs()

Interfaces

Just as you can hang a Pyramid view off any context object implementing a specific interface, you can extend any model instance implementing an interface. For example, if your model looked something like this:

from sqlalchemy.ext.declarative import declarative_base
from zope.interfaces import implementer

from .interfaces import IFilling

Base = declarative_base()

@implementer(IFilling)
class Ham(Base):
    # ...

@implementer(IFilling)
class Spam(Base):
    # ...

Then you could extend all fillings -- current and future -- with:

config.add_model_method(IFilling, get_eggs, 'get_eggs')

Limitations

Note that it's highly unlikely to be a good idea to use add_model_method to add dynamic or hybrid methods that affect the underlying sql table or mapping.

About

Pyramid framework integration to extend SQLAlchemy ORM classes with testable code.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages