Home > database >  sqlalchemy use variable for column definition
sqlalchemy use variable for column definition

Time:10-31

Let's say I have many models that all use the same type of column. e.g.

class PurchaseOrder(Model):
    unitprice = Column(Numeric(10,2))
    ...other columns

class SalesOrder(Model):
    salesprice = Column(Numeric(10,2))
    ...other columns

I would like to define some variable like;

currencyamount = Column(Numeric(10,2))

Then, if the definition ever changes I would only have one place to fix it. I would expect the model definition to look something like this now.

class PurchaseOrder(Model):
    unitprice = currencyamount
    ...other columns

If I try this I get an error along the lines of "Column object 'unitprice' already assigned to Table PurchaseOrder."

How can I go about doing this?

CodePudding user response:

I usually use a function and then call it to generate that column. Another nice thing about this is you can add args to customize the column config.

def currencyamount_col():
    return Column(Numeric(10,2))

#...

class PurchaseOrder(Model):
    unitprice = currencyamount_col()
    # ...other columns

Here is a date column factory I use:


def dt_column(default_now=True, onupdate_now=False, **override_col_kwargs):
    dt_kwargs = {
        "timezone": True
    }
    dt = DateTime(**dt_kwargs)
    col_kwargs = {}
    if default_now:
        col_kwargs['default'] = utc_now
    if onupdate_now:
        col_kwargs['onupdate'] = utc_now
    col_kwargs.update(override_col_kwargs)
    return Column(dt, **col_kwargs)

CodePudding user response:

Your object is shared around the app. It's the same reference that every class uses. Maybe you should try to use a factory method:

class PurchaseOrder(Model):
    unitprice = get_currency_column()
    ...other columns

get_currency_column():
    return Column(Numeric(10,2))

But to be frank, I would be surprised that the column definition changed that often.

CodePudding user response:

I think the cleanest way is to just create an abstract Order base class that contains your common attribute definition, and then subclass that for your different order types.

SQLAlchemy allows you to create a base class that will not be represented in the database via the __abstract__ indicator. You can define common attributes on this class. Read more here

Something like this should work for you:

class Order(Model):
    __abstract__ = True
    unitprice = Column(Numeric(10,2))

class PurchaseOrder(Order):
    ...other columns

class SalesOrder(Order):
    ...other columns

The unitprice column will be inherited by both subclasses.

  • Related