我正在尝试清理一些我想要添加到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)
更新
修复了感谢Piotr 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
当你知道怎么做时很容易!
答案 0 :(得分:1)
不要这样做。有一个概念 - validates
decorator。
属性验证器可以引发异常,暂停进程 改变属性的值,或可以改变给定的值 不同的东西。
只需在验证器中返回已修改,已过滤,干净的数据。
另请参阅Changing Attribute Behavior文档部分。