Association proxy in classical mapping keeping the business logic and the db schema separated

151 views
Skip to first unread message

Ruben Di Battista

unread,
Jul 23, 2017, 11:26:03 AM7/23/17
to sqlalchemy
Hello, 

I'm trying to introduce database persistence into an already existent class hierarchy. That mean I have in a separate module all the class representing the models of my application (without SQL interaction methods), then I have in another module the SQL schema and the mapping (so I'm using the classical mapping): 

sql.py
import sqlalchemy.orm as orm
from sqlalchemy import Metadata, Integer, String, DateTime
from myproject.models import Item, Order

metadata = MetaData()

item
= Table('item', metadata,
             
Column('id', Integer, primary_key=True),
             
Column('name', String),
             
Column('quantity', Integer)
             
)

order
= Order('order', metadata,
             
Column('id', Integer, primary_key=True),
             
Column('date', DateTime),
             )

orm
.mapper(Item, item)
orm
.mapper(Order, order)



models.py
class Item(object):
    def __init__(self, name, quantity):
        self.name = name
        self.quantity = quantity

class Order(object): 
    def __init__(self, date):
        self.date = date

Now I would like to introduce a M2M relationship with additional column in the association table:

order_item = Table('order_item', metadata,
                   Column('order_id', Integer, ForeignKey('order.id')), 
                   Column('item_id', Integer, ForeignKey('item.id')), 
                   Column('price', Float)
                  )

In the documentation, when they present the Association proxy, they do that in a declarative way. So they add an attribute to the class:
# ... Class definition ...
items = association_proxy('order_items', 'items')

Is there a way to achieve this without touching the classes in models.py? Maybe using the orm.mapper? Or the only way is to modify the class adding the association proxy like in the documentation? Do you have any reference to point me out on the right direction to use association proxies with classical mapping?

Thanks, 

PS: You find this same question on SO, if you want you can answer also there.



Mike Bayer

unread,
Jul 23, 2017, 7:50:28 PM7/23/17
to sqlal...@googlegroups.com
Basically, just do this:

orm.mapper(Order, order)
Order.items = association_proxy('order_items', 'items')

The association proxy is independent of the declarative system and if
you look in early documentation you'll see it described in terms of
classical mapping.

As far as the term "without touching the classes", there's not much
point trying to be purist about this as the call to mapper(Order,
order) highly alters the Order class in any case.


>
> Thanks,
>
> PS: You find this same question on SO, if you want you can answer also
> there.
>
>
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+...@googlegroups.com.
> To post to this group, send email to sqlal...@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

Ruben Di Battista

unread,
Jul 24, 2017, 4:40:40 AM7/24/17
to sqlal...@googlegroups.com
Thanks for taking the time to answer. 

Doing what you say means that then I have to import the models classes from the sql.py module instead of the models.py. Am I right? Or the association_proxy attribute is then available to the original class (as it happens when using mapper)?  I'm not super familiar with the automagic of SQLAlchemy...


> To post to this group, send email to sqlal...@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example.  See  http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to a topic in the Google Groups "sqlalchemy" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sqlalchemy/Od9Gzuwj9-I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to sqlalchemy+unsubscribe@googlegroups.com.

To post to this group, send email to sqlal...@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.



--
          _  
-.     .´  |∞∞∞∞
  ',  ;    |∞∞∞∞∞∞
    ˜˜     |∞∞∞∞∞∞∞∞∞ RdB 
    ,.,    |∞∞∞∞∞∞
  .'   '.  |∞∞∞∞
-'       `'

Mike Bayer

unread,
Jul 24, 2017, 9:44:44 AM7/24/17
to sqlal...@googlegroups.com
On Mon, Jul 24, 2017 at 4:40 AM, Ruben Di Battista
<rubendi...@gmail.com> wrote:
> Thanks for taking the time to answer.
>
> Doing what you say means that then I have to import the models classes from
> the sql.py module instead of the models.py. Am I right?

your top example shows the model classes Order and Item being imported
into sql.py already so that you can call mapper() on them. Based on
that setup, I proposed putting the association_proxy declaration right
there.

Or the
> association_proxy attribute is then available to the original class (as it
> happens when using mapper)? I'm not super familiar with the automagic of
> SQLAlchemy...

The association proxy is a Python descriptor, which is a basic
component of Python and worth knowing about:

https://docs.python.org/3/howto/descriptor.html
>> > email to sqlalchemy+...@googlegroups.com.
>> > To post to this group, send email to sqlal...@googlegroups.com.
>> > Visit this group at https://groups.google.com/group/sqlalchemy.
>> > For more options, visit https://groups.google.com/d/optout.
>>
>> --
>> SQLAlchemy -
>> The Python SQL Toolkit and Object Relational Mapper
>>
>> http://www.sqlalchemy.org/
>>
>> To post example code, please provide an MCVE: Minimal, Complete, and
>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
>> description.
>> ---
>> You received this message because you are subscribed to a topic in the
>> Google Groups "sqlalchemy" group.
>> To unsubscribe from this topic, visit
>> https://groups.google.com/d/topic/sqlalchemy/Od9Gzuwj9-I/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> sqlalchemy+...@googlegroups.com.
>> To post to this group, send email to sqlal...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/sqlalchemy.
>> For more options, visit https://groups.google.com/d/optout.
>
>
>
>
> --
> _
> -. .´ |∞∞∞∞
> ', ; |∞∞∞∞∞∞
> ˜˜ |∞∞∞∞∞∞∞∞∞ RdB
> ,., |∞∞∞∞∞∞
> .' '. |∞∞∞∞
> -' `'
> http://rdb.is
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages