2015-01-26 22 views
7

Veritabanımda, bazı garip biçimlerde verilerin depolandığı bazı sütunlar var. Veri tabanı başka bir kod tarafından da kullanıldığından veri formatını değiştiremiyorum. Örneğin, garip biçimlerden biri, bir zaman değerinin 23:42:30 gibi bir dize olarak temsil edilmesidir. Python tarafında her zaman datetime.time nesnesini kullanmamı sağlayan bir sihir istiyorum.SQLAlchemy: Sütun değerini iç ve veritabanı biçimi arasında ileri ve geri dönüştürme

col_raw = Column('col', String(7)) 

@property 
def col(self): 
    return datetime.strptime(self.col_raw, '%H:%M:%S').time() 
@col.setter 
def colself, t): 
    self.col_raw = t.strftime('%H:%M:%S') 

Ancak, bu yalnızca okuma ve yazma veri için sorunu çözer:

Çok basit bir çözüm gibi bir şey olurdu. Bu gibi şeyler mümkün olmazdı: hybrid extension kullanmak

Table.query.filter(Table.col == time(23,42,30)) 

bir başka yolu olacaktır. Bu şekilde, sorgulama mümkün olabilirdi, ancak doğru görsem yazmazdı. Bunun yanı sıra, her şeyi iki kez kodlamak, bir kere python kodunda ve bir kez SQL kodunda yazmayı gerektirir. (Ek sorun: Dönüşümün yalnızca SQL kodu kullanılarak yazılabileceğinden emin değilim.)

Gerçekten her ikisini birleştirmenin bir yolu yok mu? İki işlevi tanımladığım gibi, SQLAlchemy değerleri python nesnesinden dizeye ve arkaya saydam olarak dönüştürmek için kullandığı python2sql ve sql2python diyelim. Bunun, between veya like veya toplamları gibi bazı sorguları imkansız kılacağını biliyorum, ama sorun değil.

Lütfen zaman işinin yalnızca verileri dönüştürmem gereken durumlarda örnek olduğunu unutmayın; bu yüzden lütfen cevapları genel olarak tutmaya çalışın.

cevap

12

Özel biçime ve bu biçime dönüştürmeyi gerçekleştiren bir type decorator kullanın. Sütununuzu tanımlarken String yerine bu türü kullanın.

class MyTime(TypeDecorator): 
    impl = String 

    def __init__(self, length=None, format='%H:%M:%S', **kwargs) 
     super().__init__(length, **kwargs) 
     self.format = format 

    def process_literal_param(self, value, dialect): 
     # allow passing string or time to column 
     if isinstance(value, basestring): # use str instead on py3 
      value = datetime.strptime(value, self.format).time() 

     # convert python time to sql string 
     return value.strftime(self.format) if value is not None else None 

    process_bind_param = process_literal_param 

    def process_result_value(self, value, dialect): 
     # convert sql string to python time 
     return datetime.strptime(value, self.format).time() if value is not None else None 

# in your model 
class MyModel(Base): 
    time = Column(MyTime(length=7))