简体   繁体   中英

How to have default/pre-existing rows as ready to use objects using SQLAlchemy?

I'm developing a system using SQLALchemy to persist my data. I'd like to have objects of my default rows so I could use then when creating new instances.

This would be very good for me since some tables are supposed to have some default values. Imagine a simple relation between trow tables (order and order_status). When inserting values in order, it would be nice to have an easy way to use some of this default values already in order_status without having to query for them every time.

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker


engine = create_engine('sqlite:///:memory:')

Base = declarative_base()

class Order(Base):
    __tablename__ = 'order'

    id = Column(Integer, primary_key=True)
    order_status_id = Column(Integer, ForeignKey('order_status.id'))
    value = Column(Integer)

    order_status = relationship('OrderStatus', lazy=True, uselist=False)

class OrderStatus(Base):
    __tablename__ = 'order_status'

    id = Column(Integer, primary_key=True)
    name = Column(String(32))

Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

finished = OrderStatus(name='Finished')
session.add(finished)
session.commit()

For example, I'd like to create a new instance of Order using something like:

order = Order(value=10, order_status=OrderStatus.FINISHED)

Instead of:

finished_status = session.query(OrderStatus).filter_by(name='Finished').first()
order = Order(value=10, order_status=finished_status)

It does not need to be implemented exactly like my example, but I'd like something similar

You should take a look at the association_proxy : https://docs.sqlalchemy.org/en/13/orm/extensions/associationproxy.html

The example pretty much fits your question. Your Order could finally look somewhat like this (obviously not copy&paste'able):

class OrderStatus(Base):
    ...

class Order(Base):
    __tablename__ = 'order'

    id = Column(Integer, primary_key=True)
    order_status_id = Column(Integer, ForeignKey('order_status.id'))
    value = Column(Integer)

    _order_status = relationship('OrderStatus', lazy=True, uselist=False)
    order_status = association_proxy('_order_status', 'name', creator=get_or_create_order_status)

def get_or_create_order_status(name):
    # get or create a order status by name

In get_or_create_order_status you probably have to go back to querying (at least initially to eg fill a cache).

If the OrderStatus is actually as simple as in your question, maybe an enum would do the trick as well. That would obviously be much easier to manage.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM