fix: add make_proxy()
convenience method for data model Base
This commit is contained in:
parent
2289928337
commit
4a6897c6de
|
@ -25,19 +25,103 @@ Base Models
|
|||
|
||||
.. class:: Base
|
||||
|
||||
This is the base class for all data models.
|
||||
This is the base class for all :term:`data models <data model>` in
|
||||
the :term:`app database`. You should inherit from this class when
|
||||
defining custom models.
|
||||
|
||||
This class inherits from :class:`WuttaModelBase`.
|
||||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.ext.associationproxy import association_proxy
|
||||
|
||||
from wuttjamaican.db.util import (naming_convention, ModelBase,
|
||||
uuid_column, uuid_fk_column)
|
||||
|
||||
|
||||
class WuttaModelBase(ModelBase):
|
||||
"""
|
||||
Base class for data models, from which :class:`Base` inherits.
|
||||
|
||||
Custom models should inherit from :class:`Base` instead of this
|
||||
class.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def make_proxy(cls, main_class, extension, name, proxy_name=None):
|
||||
"""
|
||||
Convenience method to declare an "association proxy" for the
|
||||
main class, per the params.
|
||||
|
||||
For more info see
|
||||
:doc:`sqlalchemy:orm/extensions/associationproxy`.
|
||||
|
||||
:param main_class: Reference to the "parent" model class, upon
|
||||
which the proxy will be defined.
|
||||
|
||||
:param extension: Attribute name on the main class, which
|
||||
references the extension record.
|
||||
|
||||
:param name: Attribute name on the extension class, which
|
||||
provides the proxied value.
|
||||
|
||||
:param proxy_name: Optional attribute name on the main class,
|
||||
which will reference the proxy. If not specified, ``name``
|
||||
will be used.
|
||||
|
||||
As a simple example consider this model, which extends the
|
||||
:class:`~wuttjamaican.db.model.auth.User` class. In
|
||||
particular note the last line which is what we're documenting
|
||||
here::
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from wuttjamaican.db import model
|
||||
|
||||
class PoserUser(model.Base):
|
||||
\""" Poser extension for User \"""
|
||||
__tablename__ = 'poser_user'
|
||||
|
||||
uuid = model.uuid_column(sa.ForeignKey('user.uuid'), default=None)
|
||||
user = orm.relationship(
|
||||
model.User,
|
||||
doc="Reference to the main User record.",
|
||||
backref=orm.backref(
|
||||
'_poser',
|
||||
uselist=False,
|
||||
cascade='all, delete-orphan',
|
||||
doc="Reference to the Poser extension record."))
|
||||
|
||||
favorite_color = sa.Column(sa.String(length=100), nullable=False, doc=\"""
|
||||
User's favorite color.
|
||||
\""")
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user)
|
||||
|
||||
# nb. this is the method call
|
||||
PoserUser.make_proxy(model.User, '_poser', 'favorite_color')
|
||||
|
||||
That code defines a ``PoserUser`` model but also defines a
|
||||
``favorite_color`` attribute on the main ``User`` class, such
|
||||
that it can be used normally::
|
||||
|
||||
user = model.User(username='barney', favorite_color='green')
|
||||
session.add(user)
|
||||
|
||||
user = session.query(model.User).filter_by(username='bambam').one()
|
||||
print(user.favorite_color)
|
||||
"""
|
||||
proxy = association_proxy(
|
||||
extension, proxy_name or name,
|
||||
creator=lambda value: cls(**{name: value}))
|
||||
setattr(main_class, name, proxy)
|
||||
|
||||
|
||||
metadata = sa.MetaData(naming_convention=naming_convention)
|
||||
|
||||
Base = orm.declarative_base(metadata=metadata, cls=ModelBase)
|
||||
Base = orm.declarative_base(metadata=metadata, cls=WuttaModelBase)
|
||||
|
||||
|
||||
class Setting(Base):
|
||||
|
|
|
@ -3,12 +3,34 @@
|
|||
from unittest import TestCase
|
||||
|
||||
try:
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from wuttjamaican.db.model import base as mod
|
||||
from wuttjamaican.db.model.auth import User
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
|
||||
|
||||
class MockUser(mod.Base):
|
||||
__tablename__ = 'mock_user'
|
||||
uuid = mod.uuid_column(sa.ForeignKey('user.uuid'), default=False)
|
||||
user = orm.relationship(
|
||||
User,
|
||||
backref=orm.backref('_mock', uselist=False, cascade='all, delete-orphan'))
|
||||
favorite_color = sa.Column(sa.String(length=100), nullable=False)
|
||||
|
||||
|
||||
class TestWuttaModelBase(TestCase):
|
||||
|
||||
def test_make_proxy(self):
|
||||
self.assertFalse(hasattr(User, 'favorite_color'))
|
||||
MockUser.make_proxy(User, '_mock', 'favorite_color')
|
||||
self.assertTrue(hasattr(User, 'favorite_color'))
|
||||
user = User(favorite_color='green')
|
||||
self.assertEqual(user.favorite_color, 'green')
|
||||
|
||||
|
||||
class TestSetting(TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
|
@ -17,6 +39,7 @@ else:
|
|||
setting.name = 'foo'
|
||||
self.assertEqual(str(setting), "foo")
|
||||
|
||||
|
||||
class TestPerson(TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
|
|
Loading…
Reference in a new issue