Skip to content
This repository has been archived by the owner on Sep 5, 2019. It is now read-only.

Commit

Permalink
Merge be8c7ff into 4ecbd60
Browse files Browse the repository at this point in the history
  • Loading branch information
msom committed Oct 12, 2018
2 parents 4ecbd60 + be8c7ff commit f66d588
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 3 deletions.
8 changes: 6 additions & 2 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Changelog
---------

- Allows multiple associations per model.
[msom]

0.73.1 (2018-10-11)
~~~~~~~~~~~~~~~~~~~

Expand All @@ -10,12 +14,12 @@ Changelog
~~~~~~~~~~~~~~~~~~~

- Moves the yubikey related functions to the core (from onegov.user).

In the future, it might make sense to move this to a onegov.otp package. In
any case, onegov.user is not the right place as the integraiton happens in
onegov.core as it is and the user model should not be a prerequisite for
yubikeys.

[href]

0.72.5 (2018-10-04)
Expand Down
6 changes: 5 additions & 1 deletion onegov/core/orm/abstract/associable.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ class Company(Base, Addressable):
uselist = not cardinality.endswith('to-one')

def descriptor(cls):
name = '_for_'.join((associated_cls.__tablename__, cls.__tablename__))
name = '{}_for_{}_{}'.format(
associated_cls.__tablename__,
cls.__tablename__,
attribute_name
)
key = '{}_id'.format(cls.__tablename__)
target = '{}.id'.format(cls.__tablename__)
backref = 'linked_{}'.format(cls.__tablename__)
Expand Down
85 changes: 85 additions & 0 deletions onegov/core/tests/test_orm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,91 @@ class Person(Base, Addressable):
assert session.query(Address).count() == 1


def test_associable_multiple(postgres_dsn):
Base = declarative_base(cls=ModelBase)

class Address(Base, Associable):
__tablename__ = 'adresses'

id = Column(Integer, primary_key=True)
town = Column(Text, nullable=False)

class Person(Base, Associable):
__tablename__ = 'people'

id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)

address = associated(Address, 'address', 'one-to-one')

class Company(Base):
__tablename__ = 'companies'

id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)

address = associated(Address, 'address', 'one-to-one')
employee = associated(Person, 'employee', 'one-to-many')

mgr = SessionManager(postgres_dsn, Base)
mgr.set_current_schema('testing')

session = mgr.session()

session.add(Company(
name='Engulf & Devour',
address=Address(town='Ember'),
employee=[
Person(name='Alice', address=Address(town='Alicante')),
Person(name='Bob', address=Address(town='Brigadoon'))
]
))

company = session.query(Company).first()
assert company.address.town == "Ember"
assert {e.name: e.address.town for e in company.employee} == {
'Alice': 'Alicante', 'Bob': 'Brigadoon'
}

alice = session.query(Person).filter_by(name="Alice").one()
assert alice.address.town == "Alicante"
assert alice.linked_companies == [company]
assert alice.links.count() == 1

bob = session.query(Person).filter_by(name="Bob").one()
assert bob.address.town == "Brigadoon"
assert bob.linked_companies == [company]
assert bob.links.count() == 1

addresses = session.query(Address).all()
assert session.query(Address).count() == 3

assert addresses[0].links.count() == 1
assert addresses[0].links.first().name == "Engulf & Devour"
assert len(addresses[0].linked_companies) == 1
assert len(addresses[0].linked_people) == 0

assert addresses[1].links.count() == 1
assert addresses[1].links.first().name == "Alice"
assert len(addresses[1].linked_companies) == 0
assert len(addresses[1].linked_people) == 1

assert addresses[2].links.count() == 1
assert addresses[2].links.first().name == "Bob"
assert len(addresses[2].linked_companies) == 0
assert len(addresses[2].linked_people) == 1

session.delete(alice)
session.flush()

assert session.query(Address).count() == 2

session.delete(addresses[2])
session.flush()

assert session.query(Company).first().address.town == 'Ember'


def test_selectable_sql_query(session):
stmt = as_selectable("""
SELECT
Expand Down
22 changes: 22 additions & 0 deletions onegov/core/upgrades.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,25 @@ def json_columns(cls):
# commits/rolls back the current transaction (to keep the number
# of required locks to a minimum)
yield True


@upgrade_task('Rename associated tables')
def rename_associated_tables(context):
bases = set()

for cls in find_models(Base, lambda cls: issubclass(cls, Associable)):
bases.add(cls.association_base())

for base in bases:
for link in base.registered_links.values():
new_name = link.table.name
old_name = new_name[:new_name.rfind(link.attribute)].rstrip('_')
if new_name == old_name:
continue

if context.has_table(old_name) and context.has_table(new_name):
# the new table has probably already been made by the ORM
context.operations.drop_table(new_name)

if context.has_table(old_name) and not context.has_table(new_name):
context.operations.rename_table(old_name, new_name)

0 comments on commit f66d588

Please sign in to comment.