2017-01-30 19 views
0

我想清理我想要添加到一個數據庫SQLAlchemy的,以確保它是正確的類型的一些舉步維艱的數據。所以我正在嘗試將字符串截斷爲正確的列長度。使用SETATTR和__init__清理的SQLAlchemy數據

我試着創建一個構造函數,然後使用getattr()setattr()試圖強制執行此操作。但由於某些原因字符串不被截斷等。任何建議?

class Property(Base): 
    """ 
    Property details as imported from various Council sources 
    """ 
    MAXPROPREFLEN = 20 
    MAXADDRESSLEN = 100 
    MAXDESCRIPLEN = 120 
    MAXPOSTCODELEN = 10 

    __tablename__ = 'properties' 
    id    = Column(Integer, primary_key=True) 
    PropertyRef = Column(String(MAXPROPREFLEN)) # Council reference, diffrerent from UPRN 
    AccountHolder = Column(String(MAXDESCRIPLEN)) 
    Address1  = Column(String(MAXADDRESSLEN)) 
    Address2  = Column(String(MAXADDRESSLEN)) 
    Address3  = Column(String(MAXADDRESSLEN)) 
    Address4  = Column(String(MAXADDRESSLEN)) 
    PostCode  = Column(String(MAXPOSTCODELEN), index=True) 
    UPRN   = Column(BigInteger) 
    Description = Column(String(MAXDESCRIPLEN)) 
    RV    = Column(Numeric(10, 0)) 
    Empty   = Column(Boolean) 
    LiableFrom  = Column(Date) 
    EmptySince  = Column(Date) 
    MEBID   = Column(Integer) # Key in MEB table if applicable 
    Authority  = Column(Integer) # Key in authorities table 

    def __init__(self, **kwargs): 
     """ 
     Ordinarily we wouldn't require a constructor, but the data from the 
     various LAs is of such poor quality and the Psycopg2 connector 
     so strict about types that we have to clean it up. So we need to 
     truncate overly long strings etc. 
     """ 
     for key, value in kwargs.items(): 
      if key == 'PropertyRef': 
       setattr(self, key, value[:Property.MAXPROPREFLEN] if value else None) 
      elif key == 'PostCode': 
       setattr(self, key, value[:Property.MAXPOSTCODELEN] if value else None) 
      elif key in ['AccountHolder', 'Description']: 
       if type(value) is str: 
        setattr(self, key, value[:Property.MAXDESCRIPLEN]) 
       else: 
        setattr(self, key, None) 
      elif key in ['Address1', 'Address2', 'Address3', 'Address4']: 
       setattr(self, key, value[:Property.MAXADDRESSLEN] if value else None) 
      elif key in ['LiableFrom','EmptySince']: 
       if type(value) == datetime.datetime: 
        setattr(self, key, value.date()) 
       elif type(value) == datetime.date: 
        setattr(self, key, value) 
       else: 
        setattr(self, key, None) 
      if key == 'UPRN': 
       if type(value) is str: 
        try: 
         setattr(self, key, int(value)) 
        except ValueError: 
         setattr(self, key, None) 
       elif type(value) is int: 
        setattr(self, key, value) 
       else: 
        setattr(self, key, None) 
      else: 
       setattr(self, key, value) 

UPDATE

固定的,感謝彼得·Dawidiuk。它現在是

class Property(Base): 
    """ 
    Property details as imported from various Council sources 
    """ 
    MAXPROPREFLEN = 20 
    MAXADDRESSLEN = 80 
    MAXDESCRIPLEN = 80 
    MAXPOSTCODELEN = 10 

    __tablename__ = 'properties' 
    id    = Column(Integer, primary_key=True) 
    PropertyRef = Column(String(MAXPROPREFLEN)) # Council reference, diffrerent from UPRN 
    AccountHolder = Column(String(MAXDESCRIPLEN)) 
    Address1  = Column(String(MAXADDRESSLEN)) 
    Address2  = Column(String(MAXADDRESSLEN)) 
    Address3  = Column(String(MAXADDRESSLEN)) 
    Address4  = Column(String(MAXADDRESSLEN)) 
    PostCode  = Column(String(MAXPOSTCODELEN), index=True) 
    UPRN   = Column(BigInteger) 
    Description = Column(String(MAXDESCRIPLEN)) 
    RV    = Column(Numeric(10, 0)) 
    Empty   = Column(Boolean) 
    LiableFrom  = Column(Date) 
    EmptySince  = Column(Date) 
    MEBID   = Column(Integer) # Key in MEB table if applicable 
    Authority  = Column(Integer) # Key in authorities table 


    @validates('PropertyRef', 'AccountHolder', 'Description', 
       'Address1', 'Address2', 'Address3', 'Address4', 'PostCode') 
    def ValidateString(self, key, value): 
     maxlengths = {'PropertyRef': Property.MAXPROPREFLEN, 
         'AccountHolder': Property.MAXDESCRIPLEN, 
         'Description': Property.MAXDESCRIPLEN, 
         'Address1':  Property.MAXADDRESSLEN, 
         'Address2':  Property.MAXADDRESSLEN, 
         'Address3':  Property.MAXADDRESSLEN, 
         'Address4':  Property.MAXADDRESSLEN, 
         'PostCode':  Property.MAXPOSTCODELEN 
         } 

     if type(value) is str: 
      value = value.strip().upper() 
      if len(value) > maxlengths[key]: 
       logger.debug("Timmming {} <{}> to <{}> ({} to {} chars)".format(
          key, value, value[:maxlengths[key]], 
          len(value), maxlengths[key])) 
      return value[:maxlengths[key]] 
     else: 
      return None 

    @validates('LiableFrom', 'EmptySince') 
    def ValidateDate(self, key, value): 
     if type(value) == datetime.datetime: 
      return value.date() 
     elif type(value) == datetime.date: 
      return value 
     else: 
      return None 

    @validates('UPRN') 
    def ValidateInteger(self, key, value): 
     try: 
      return int(value) 
     except: 
      return None 

    @validates('RV') 
    def ValidateFloat(self, key, value): 
     try: 
      return float(value) 
     except: 
      return None 

很容易,當你知道如何!

回答

1

不要這樣。這是一個概念 - validatesdecorator

的屬性驗證可引發異常,制止 過程變異屬性的值,或可以改變給定值到 不同的東西

剛剛返回修改驗證,過濾,乾淨的數據。

另請參閱Changing Attribute Behavior文檔部分。