Я пытаюсь использовать поле SQLAlchemy PickleType
для пользовательского объекта, который у меня есть.
вот моя модель:
class RouteModelStore(db.Model):
__tablename__ = 'route_model_store'
id = db.Column(db.Integer, primary_key=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow)
origin = db.Column(db.String(255), index=True, nullable=False)
dest = db.Column(db.String(255), index=True, nullable=False)
route_key = db.Column(db.String(255))
model = db.Column(db.PickleType, nullable=False) # this field
scores = db.Column(db.PickleType, nullable=False)
resolution = db.Column(db.String(255), nullable=False)
def __repr__(self):
return f"<RouteModel {self.origin}-{self.dest}>"
У меня изначально было только что определено поле PickleType
, но после сохранения моего пользовательского объекта и загрузки его из БД я получаю эту ошибку:
model = RouteModel.query.filter(RouteModel.origin=='MKE', RouteModel.dest=='ATL')
model.model
AttributeError: 'RouteModel' object has no attribute '_sa_instance_state'
Я подумал, что это может быть из-за того, что ORM не знает, как десериализовать этот объект поэтому я создал настраиваемое поле через TypeDecorator
с настраиваемым расширителем:
class CustomUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if name == 'RouteModel':
return RouteModel
return super().find_class(module, name)
class RouteModelPickle(types.TypeDecorator):
impl = types.PickleType
def convert_bind_param(self, value, engine):
result = self.impl.convert_bind_param(value, engine)
return result
def process_result_value(self, value, dialect):
return CustomUnpickler(
io.BytesIO(value.read())).load()
, затем я изменил поле модели для этого нового типа столбца:
model = db.Column (RouteModelPickle, nullable = False)
однако теперь, когда я запускаю миграцию, я получаю ошибку:
File "<frozen importlib._bootstrap_external>", line 674, in exec_module
File "<frozen importlib._bootstrap_external>", line 781, in get_code
File "<frozen importlib._bootstrap_external>", line 741, in source_to_code
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/Users/cyrusghazanfar/Desktop/pilota/pilota_project/pilota_ml/migrations/versions/f49bcb85c25f_.py", line 28
sa.Column('model', app.models.RouteModelPickle(pickler=<module 'pickle' from '/Users/cyrusghazanfar/anaconda3/lib/python3.6/pickle.py'>), nullable=False),
вот миграция, созданная (python manage.py db migrate
)
def upgrade():
...
sa.Column('model', app.models.RouteModelPickle(pickler=<module 'pickle' from '/Users/cyrusghazanfar/anaconda3/lib/python3.6/pickle.py'>), nullable=False),
...
Ох, и вот фактический объект, который я пытаюсь выбрать, сохранить / загрузить из БД:
class RouteModel:
def __init__(self, route, pred_type='crs_arr'):
self.route = route
self.pred_type = pred_type
self.rm_key = route[2:5] + '_' + route[9:12] + '_' + pred_type
self.f_select = None
self.model = None
def train_model(self, x_train, y_train, time_cols):
self.model = fit_rf(x_train, y_train)
self.f_select = get_f_select(self.model, x_train, time_cols, num_f=20)
self.model = fit_rf_cv(x_train[self.f_select],
y_train).best_estimator_.fit(x_train[self.f_select], y_train)
def retrain_model(self, x_train, y_train):
self.model = self.model.fit(x_train[self.f_select], y_train)
def predict(self, x_pred):
y_pred = self.model.predict(x_pred[self.f_select])
return y_pred
def predict_prob(self, x_pred):
y_pred_prob = self.model.predict_proba(x_pred[self.f_select])
return y_pred_prob
Любая помощь, пожалуйста:)