Chrim
Chrim

Reputation: 100

How can sqlalchemy work with custom class as the attributes

I am using sqlalchemy and flask-sqlalchemy, one of my db model comes with a state column

class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(8))
    state = db.Column(db.Integer, default=ServerState.IN_PACKAGE, nullable=True)

    def init_state(self):

        self.state = State1

    def transit_state(self):

        self.state.next(self) 

The problem is that this state column is saved into db as a integer, but in order to implement a proper state machine, it is implemented as a Class:

class State1(BaseState):

    __int = 100
    __name = 'State1'

    @staticmethod
    def next(item):
        if item.contidition1 is None or item.condition2 is None:
            raise InvalidStateTransition

        item.state = State2

This works well and keeps the code clean, but the critical issue is that when I want to commit the Item to the db, it surely will give me error :

 Incorrect integer value: '<class 'app.models.Item.State1'>' for column 'state' at row 1

So, is there a way for the session, or python, to automatically convert the class to its int representation when save into the db, and convert from the int to its state class when it is retrieved from the db?

Upvotes: 0

Views: 1197

Answers (1)

univerio
univerio

Reputation: 20518

You can use a TypeDecorator. Something like:

class StateType(TypeDecorator):
    impl = Integer

    def process_bind_param(self, value, dialect):
        return map_integer_to_my_state(value)

    def process_result_value(self, value, dialect):
        return map_my_state_to_integer(value)

Then you can use StateType as the type of the state column:

state = db.Column(StateType, ...)

Upvotes: 2

Related Questions