首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在SQLAlchemy中,是否有一种象征性地创建真正创建两列的列的方法?

在SQLAlchemy中,是否有一种象征性地创建真正创建两列的列的方法?
EN

Stack Overflow用户
提问于 2020-08-13 11:47:51
回答 2查看 59关注 0票数 1

考虑以下代码:

代码语言:javascript
复制
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值分割成两个数据库列。

当然,我更喜欢创建自己的列类型:

代码语言:javascript
复制
class Appointment(Base):
    scheduled_date = Column(MyDatetimeAware())

问题是scheduled_date不仅仅是一个列,它需要多个列。有什么方法可以在SQLAlchemy中推广多列“数据类型”吗?

EN

回答 2

Stack Overflow用户

发布于 2020-08-13 12:04:25

您正在考虑hybrid properties(参见文档)。它们可以用于显示SQL python设置中的不同行为,但也可以用于预定义某些转换。我经常使用它们将UTC时间戳转换为本地时区。请注意,您定义了属性1-3次。一次作为python属性,一次用于您希望SQL如何工作,一次用于setter。

代码语言:javascript
复制
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__包装器的混合器。

代码语言:javascript
复制
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对象:

代码语言:javascript
复制
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()
票数 0
EN

Stack Overflow用户

发布于 2020-08-13 14:53:20

在时区感知日期时间列的特定情况下,可以使用支持后端的时间戳列类型。通常,如果要使用实际表示多列的字段,则可以使用组合柱型。但是,这需要您单独指定列。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63394500

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档