2017-10-14 28 views
1

Utilisation de SQLAlchemy J'ai défini mon propre TypeDecorator pour stocker des données DataFrames pandas dans une base de données codée en tant que chaîne JSON.SQLAlchemy TypeDécorateurs et erreurs de comparaison

class db_JsonEncodedDataFrameWithTimezone(db.TypeDecorator): 
    impl = db.Text 

    def process_bind_param(self, value, dialect): 
     if value is not None and isinstance(value, pd.DataFrame): 
      timezone = value.index.tz.zone 
      df_json = value.to_json(orient="index") 
      data = {'timezone': timezone, 'df': df_json, 'index_name': value.index.name} 
      value = json.dumps(data) 
     return value 

    def process_result_value(self, value, dialect): 
     if value is not None: 
      data = json.loads(value) 
      df = pd.read_json(data['df'], orient="index") 
      df.index = df.index.tz_localize('UTC') 
      df.index = df.index.tz_convert(data['timezone']) 
      df.index.name = data['index_name'] 
      value = df 
     return value 

Cela fonctionne très bien pour la première sauvegarde de la base de données, et le chargement est également possible. Le problème survient lorsque j'augmente la valeur, c'est-à-dire que je modifie le DataFrame et que j'essaie de modifier la base de données. Quand j'invoque

db.session.add(entity) 
db.session.commit() 

Je reçois un retraçage qui pointe à la comparaison des valeurs étant le problème:

x == y 
ValueError: Can only compare identically-labeled DataFrame Objects. 

Je soupçonne que mon problème a quelque chose à voir avec les comparateurs exerçant la contrainte. J'ai essayé trois choses, tous ont échoué et je ne sais vraiment pas quoi faire:

#1st failed solution attempt inserting 
coerce_to_is_types = (pd.DataFrame,) 

#2nd failed solution attempt inserting 
def coerce_compared_value(self, op, value): 
    return self.impl.coerce_compared_value(op, value) 

#3rd failed solution attempt 
class comparator_factory(db.Text.comparator_factory): 
    def __eq__(self, other): 
     try: 
      value = (self == other).all().all() 
     except ValueError: 
      value = False 
     return value 

Répondre

0

Au quatrième essai, je pense avoir trouvé la réponse, je crée directement ma propre fonction de comparaison que j'inséré dans la classe Type ci-dessus. Cela évite l'opérateur « x == y » étant réalisée sur mes DataFrames:

def compare_values(self, x, y): 
    from pandas.util.testing import assert_frame_equal 
    try: 
     assert_frame_equal(x, y, check_names=True, check_like=True) 
     return True 
    except (AssertionError, ValueError, TypeError): 
     return False 

Un autre problème de cette nature est apparu plus tard dans mon code. La solution était d'amender le ci-dessus pour essayer le naturel comparer d'abord et si cela a échoué alors mettre en œuvre ce qui précède:

try: 
    value = x == y 
except: 
    # some other overwriting comparision method such as above