考虑以下代码:
class Appointment(Base):
scheduled_date_utc = Column(DateTime) # Naive UTC
scheduled_date_timezone = Column(TimezoneType()) # TimezoneType is from sqlalchemy-utils
@property
def scheduled_date(self) -> datetime:
... (assembles scheduled_date_utc and
scheduled_date_timezone into a unified object)
@scheduled_date.setter
def scheduled_date(self, value: datetime):
... (splits up tz-aware datetime into naive UTC time,
and timezone column, and sets them separately)不要太担心属性方法,但是要理解它们有一个Python值,然后必须将这个Python值分割成两个数据库列。
当然,我更喜欢创建自己的列类型:
class Appointment(Base):
scheduled_date = Column(MyDatetimeAware())问题是scheduled_date不仅仅是一个列,它需要多个列。有什么方法可以在SQLAlchemy中推广多列“数据类型”吗?
发布于 2020-08-13 12:04:25
您正在考虑hybrid properties(参见文档)。它们可以用于显示SQL python设置中的不同行为,但也可以用于预定义某些转换。我经常使用它们将UTC时间戳转换为本地时区。请注意,您定义了属性1-3次。一次作为python属性,一次用于您希望SQL如何工作,一次用于setter。
import pytz
from sqlalchemy.ext.hybrid import hybrid_property
class Appointment(Base):
scheduled_date_utc = Column(DateTime) # Naive UTC
scheduled_date_timezone = Column(TimezoneType()) # TimezoneType is from sqlalchemy-utils
@property
def scheduled_date(self) -> datetime:
# see https://stackoverflow.com/a/18646797/5015356
return self.scheduled_date_utc\
.replace(tzinfo=pytz.utc)\
.astimezone(pytz.timezone(self.scheduled_date_timezone))
@scheduled_date.expr
def scheduled_date(cls):
return func.timezone(cls.scheduled_date_timezone, cls.scheduled_date_utc)要使解决方案可重用,可以编写带有__setattr__包装器的混合器。
import pytz
class TimeZoneMixin:
def is_timezone_aware_attr(self, attr):
return hasattr(self, attr + '_utc') and hasattr(self, attr + '_timezone')
def __getattr__(self, attr):
"""
__getattr__ is only called as a last resort, if no other
matching columns exist
"""
if self.is_timezone_aware_attr(attr):
return func.timezone(getattr(self, attr + '_utc'),
getattr(self, attr + '_timezone'))
raise AttributeError()
def __setattr__(self, attr, value):
if self.is_timezone_aware_attr(attr):
setattr(self, attr + '_utc', value.astimezone(tzinfo=pytz.utc))
setattr(self, attr + '_utc', value.tzinfo)
raise AttributeError()或者让它只使用一个共享的timezone对象:
import pytz
class TimeZoneMixin:
timezone = Column(TimezoneType())
def is_timezone_aware_attr(self, attr):
return hasattr(self, attr + '_utc')
def __getattr__(self, attr):
"""
__getattr__ is only called as a last resort, if no other
matching columns exist
"""
if self.is_timezone_aware_attr(attr):
return func.timezone(getattr(self, attr + '_utc'), self.timezone)
raise AttributeError()
def __setattr__(self, attr, value):
if self.is_timezone_aware_attr(attr):
setattr(self, attr + '_utc', value.astimezone(tzinfo=pytz.utc))
self.timezone = value.tzinfo
raise AttributeError()https://stackoverflow.com/questions/63394500
复制相似问题