Add string arg support for generic relationship
This commit is contained in:
@@ -47,4 +47,34 @@ Generic relationship is a form of relationship that supports creating a 1 to man
|
|||||||
# Find any events that are bound to users.
|
# Find any events that are bound to users.
|
||||||
session.query(Event).filter(Event.object.is_type(User)).all()
|
session.query(Event).filter(Event.object.is_type(User)).all()
|
||||||
|
|
||||||
.. _colour: https://github.com/vaab/colour
|
|
||||||
|
Using generic_relationship with abstract base classes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Generic relationships also allows using string arguments. When using generic_relationship with abstract base classes you need to set up the relationship using declared_attr decorator and string arguments.
|
||||||
|
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
|
||||||
|
class Building(self.Base):
|
||||||
|
__tablename__ = 'building'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
class User(self.Base):
|
||||||
|
__tablename__ = 'user'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
class EventBase(self.Base):
|
||||||
|
__abstract__ = True
|
||||||
|
|
||||||
|
object_type = sa.Column(sa.Unicode(255))
|
||||||
|
object_id = sa.Column(sa.Integer, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def object(cls):
|
||||||
|
return generic_relationship('object_type', 'object_id')
|
||||||
|
|
||||||
|
class Event(EventBase):
|
||||||
|
__tablename__ = 'event'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import six
|
||||||
|
|
||||||
from sqlalchemy.orm.interfaces import MapperProperty, PropComparator
|
from sqlalchemy.orm.interfaces import MapperProperty, PropComparator
|
||||||
from sqlalchemy.orm.session import _state_session
|
from sqlalchemy.orm.session import _state_session
|
||||||
from sqlalchemy.orm import attributes, class_mapper
|
from sqlalchemy.orm import attributes, class_mapper
|
||||||
@@ -86,6 +88,8 @@ class GenericRelationshipProperty(MapperProperty):
|
|||||||
def __init__(self, discriminator, id, doc=None):
|
def __init__(self, discriminator, id, doc=None):
|
||||||
self._discriminator_col = discriminator
|
self._discriminator_col = discriminator
|
||||||
self._id_col = id
|
self._id_col = id
|
||||||
|
self._id = None
|
||||||
|
self._discriminator = None
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
|
|
||||||
set_creation_order(self)
|
set_creation_order(self)
|
||||||
@@ -98,6 +102,16 @@ class GenericRelationshipProperty(MapperProperty):
|
|||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
# Resolve columns to attributes.
|
# Resolve columns to attributes.
|
||||||
|
if isinstance(self._discriminator_col, six.string_types):
|
||||||
|
self._discriminator_col = self.parent.columns[
|
||||||
|
self._discriminator_col
|
||||||
|
]
|
||||||
|
|
||||||
|
if isinstance(self._id_col, six.string_types):
|
||||||
|
self._id_col = self.parent.columns[
|
||||||
|
self._id_col
|
||||||
|
]
|
||||||
|
|
||||||
self.discriminator = self._column_to_property(self._discriminator_col)
|
self.discriminator = self._column_to_property(self._discriminator_col)
|
||||||
self.id = self._column_to_property(self._id_col)
|
self.id = self._column_to_property(self._id_col)
|
||||||
|
|
||||||
|
@@ -2,35 +2,14 @@ from __future__ import unicode_literals
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from tests import TestCase
|
from tests import TestCase
|
||||||
from sqlalchemy_utils import generic_relationship
|
from sqlalchemy_utils import generic_relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
|
||||||
|
|
||||||
class TestGenericForiegnKey(TestCase):
|
class GenericRelationshipTestCase(TestCase):
|
||||||
|
|
||||||
def create_models(self):
|
|
||||||
class Building(self.Base):
|
|
||||||
__tablename__ = 'building'
|
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
|
||||||
|
|
||||||
class User(self.Base):
|
|
||||||
__tablename__ = 'user'
|
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
|
||||||
|
|
||||||
class Event(self.Base):
|
|
||||||
__tablename__ = 'event'
|
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
|
||||||
|
|
||||||
object_type = sa.Column(sa.Unicode(255), name="objectType")
|
|
||||||
object_id = sa.Column(sa.Integer, nullable=False)
|
|
||||||
|
|
||||||
object = generic_relationship(object_type, object_id)
|
|
||||||
|
|
||||||
self.Building = Building
|
|
||||||
self.User = User
|
|
||||||
self.Event = Event
|
|
||||||
|
|
||||||
def test_set_as_none(self):
|
def test_set_as_none(self):
|
||||||
event = self.Event()
|
event = self.Event()
|
||||||
event.object = None
|
event.object = None
|
||||||
|
assert event.object is None
|
||||||
|
|
||||||
def test_set_manual_and_get(self):
|
def test_set_manual_and_get(self):
|
||||||
user = self.User()
|
user = self.User()
|
||||||
@@ -128,3 +107,56 @@ class TestGenericForiegnKey(TestCase):
|
|||||||
statement = self.Event.object.is_type(self.User)
|
statement = self.Event.object.is_type(self.User)
|
||||||
q = self.session.query(self.Event).filter(statement)
|
q = self.session.query(self.Event).filter(statement)
|
||||||
assert q.first() is not None
|
assert q.first() is not None
|
||||||
|
|
||||||
|
|
||||||
|
class TestGenericRelationship(GenericRelationshipTestCase):
|
||||||
|
def create_models(self):
|
||||||
|
class Building(self.Base):
|
||||||
|
__tablename__ = 'building'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
class User(self.Base):
|
||||||
|
__tablename__ = 'user'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
class Event(self.Base):
|
||||||
|
__tablename__ = 'event'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
object_type = sa.Column(sa.Unicode(255), name="objectType")
|
||||||
|
object_id = sa.Column(sa.Integer, nullable=False)
|
||||||
|
|
||||||
|
object = generic_relationship(object_type, object_id)
|
||||||
|
|
||||||
|
self.Building = Building
|
||||||
|
self.User = User
|
||||||
|
self.Event = Event
|
||||||
|
|
||||||
|
|
||||||
|
class TestGenericRelationshipWithAbstractBase(GenericRelationshipTestCase):
|
||||||
|
def create_models(self):
|
||||||
|
class Building(self.Base):
|
||||||
|
__tablename__ = 'building'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
class User(self.Base):
|
||||||
|
__tablename__ = 'user'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
class EventBase(self.Base):
|
||||||
|
__abstract__ = True
|
||||||
|
|
||||||
|
object_type = sa.Column(sa.Unicode(255))
|
||||||
|
object_id = sa.Column(sa.Integer, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def object(cls):
|
||||||
|
return generic_relationship('object_type', 'object_id')
|
||||||
|
|
||||||
|
class Event(EventBase):
|
||||||
|
__tablename__ = 'event'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
self.Building = Building
|
||||||
|
self.User = User
|
||||||
|
self.Event = Event
|
||||||
|
Reference in New Issue
Block a user