Skip to content

Instantly share code, notes, and snippets.

@miohtama
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miohtama/844cc78bcf1d317e31ca to your computer and use it in GitHub Desktop.
Save miohtama/844cc78bcf1d317e31ca to your computer and use it in GitHub Desktop.
Deferred declared_attr for Pyramid and SQLAlchemy. This is an example how to detact your SQLAlchemy models from declarative base class and database session, so that you can made them configurable for the third party. Your library can contain declared_attr directives which can be filled in by Pyramid configuration. E.g. your library expects the h…
"""websauna.referral library initialization code."""
import logging
from sqlalchemy.ext.declarative import instrument_declarative
from pyramid_web20.system.model import Base
from . import models
logger = logging.getLogger(__name__)
def instrument_models(config):
"""Configure concrete model to be included within the host application.
Defer ``@declared_attr`` resolution until we have Pyramid configuration available.
This resolves the references to the user model and runs all decorations on the model implementations.
You must call this before the host application calls ``Base
"""
# Resolve @declared_attr on Referral model
instrument_declarative(models.ReferralProgram, Base._decl_class_registry, Base.metadata)
from myapp.models import Base
# Attach pyramid configuration object to SQLAlchemy declarative metadata, so it can be accessed by models
Base.metadata.pyramid_config = config
# Run instrumented_models() initialization to all libraries before you bind your database session
configure_instrumented_models(settings)
# Now your SQLAlchemy is aware of third party library cross references
engine = engine_from_config(settings, 'sqlalchemy.', connect_args={"options": "-c timezone=utc"}, client_encoding='utf8')
models.DBSession.configure(bind=engine)
import datetime
from sqlalchemy import (
Column,
Index,
Integer,
String, DateTime, ForeignKey)
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm import relationship
utc = datetime.timezone.utc
def now():
"""Get timezone-aware UTC timestamp."""
return datetime.datetime.now(datetime.timezone.utc)
class ReferralProgram:
"""A referral program.
A referral program can by set by the system (owned by nobody) or created by some site user. For the user created referral programs there is usually some incentive like get free Apple Watch if you tell about this website to your 20 friends.
Each referral program gets its own slug which is a HTTP GET query parameter attached to incoming links. When the a visitor lands on the site through one of these links, the viistor is marked with a permacookie to belonging to the referral program. If this visitor ever converts to user, i.e. signs up, the referral program owner can be credited for bringing in a new user.
System set referral programs are good for tracking your advertisement links internally.
"""
__tablename__ = 'referral_program'
id = Column(Integer, primary_key=True)
created_at = Column(DateTime(timezone=utc), default=now)
updated_at = Column(DateTime(timezone=utc), onupdate=now)
slug = Column(String(6), unique=True)
hits = Column(Integer, default=0)
@declared_attr
def owner(cls):
"""The owner of this referral program.
If you do not like the default implementation, you can subclass ReferralProgram and then override ``owner`` and ``owner_id`` SQLALchemy declared attributes. Then you call ``instrument_declarative()`` to your custom model implementation, instead of the default ``ReferralProgram``.
"""
from pyramid_web20.system.user.utils import get_user_class
config = cls.metadata.pyramid_config
User = get_user_class(config.registry)
return relationship(User, backref="referral_programs")
@declared_attr
def owner_id(cls):
from pyramid_web20.system.user.utils import get_user_class
config = cls.metadata.pyramid_config
User = get_user_class(config.registry)
return Column(Integer, ForeignKey('{}.id'.format(User.__tablename__)))
#: For quick resolution if referrals
Index('referral_slug_index', ReferralProgram.slug, unique=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment