Given a couple of simple tables in sqlalchemy which have a simple one to many relationship, I am trying to write a generalized function to add children to the relationship collection.  The tables look like this:
class StockItem(Base):
    __tablename__ = 'stock_items'
    stock_id = Column(Integer, primary_key=True)
    description = Column(String, nullable=False, unique=True)
    department = Column(String)
    images = relationship('ImageKey', backref='stock_item', lazy='dynamic')
    def __repr__(self):
        return '<StockItem(Stock ID:{}, Description: {}, Department: {})>'.\
            format(self.stock_id, self.description, self.department)
class ImageKey(Base):
    __tablename__ = 'image_keys'
    s3_key = Column(String, primary_key=True)
    stock_id = Column(Integer, ForeignKey('stock_items.stock_id'))
    def __repr__(self):
        return '<ImageKey(AWS S3 Key: {}, Stock Item: {})>'.\
            format(self.s3_key, self.stock_id)
So with the given setup, I can add items to the images collection for a given StockItem:
item = StockItem(stock_id=42, description='Frobnistication for Foozlebars', 
                 department='Books')
image = ImageKey(s3_key='listings/images/Frob1.jpg', stock_id=42)
item.images.append(image)
Ok.  so far so good. In reality, my app is going to have several tables with relationships. My issue arises when I try to generalize this out to a function to handle arbitrary relationships.  Here'e what I wrote (note, add_item() is just a method which wraps an object construction with a try/except to handle IntegrityError's):
@session_manager
def _add_collection_item(self, Parent, Child, key, collection,
                         session=None, **kwargs):
    """Add a Child object to the collection object of Parent."""
    child = self.add_item(Child, session=session, **kwargs)
    parent = session.query(Parent).get(key)
    parent.collection.append(child)  # This line obviously throws error.
    session.add(parent)
I call the function like:
db._add_collection_item(StockItem, ImageKey, 42, 'images',
                        s3_key='listings/images/Frob1.jpg',
                        stock_id=42)
which obviously errors because the parent table has no collection attribute.  Traceback:
Traceback (most recent call last):
  File "C:\Code\development\pyBay\demo1.py", line 25, in <module>
    stock_id=1)
  File "C:\Code\development\pyBay\pybay\database\client.py", line 67, in add_context_manager
    result = func(self, *args, session=session, **kwargs)
  File "C:\Code\development\pyBay\pybay\database\client.py", line 113, in _add_collection_item
    parent.collection.append(child)
AttributeError: 'StockItem' object has no attribute 'collection'
I think it would throw an error anyway since the collection name is passed as a string.
So my question, is how can I add an item to the collection by key word instead of using 'dot' notation?
Do:
  getattr(parent, collection).append(child)
More info
https://docs.python.org/2/library/functions.html#getattr
https://docs.python.org/3.4/library/functions.html#getattr
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With