具有默认检查相同表的列

时间:2014-10-25 13:18:13

标签: python sqlalchemy

使用SQLAlchemy,我想自动生成模型的标识符:

class Foo(Model):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    date = Column(Date, default=datetime.now)
    reference = Column(Unicode, default=generate_reference)

基本上,我希望generate_reference返回一个字段,如:

FOO201410-001

其中2014是当前年份,10当前月份和001当前月份的下一个ID,使用以下查询计算:

SELECT COUNT(*)
  FROM foo
 WHERE strftime('%m', datetime(date, 'unixepoch')) == strftime('%m', date('now'))
   AND strftime('%y', datetime(date, 'unixepoch')) == strftime('%y', date('now'))

我从SQLite3中读到的语法形式,虽然它只是一个例子。基本上,我想知道有多少其他记录具有相同的月/年,并为最后一部分分配该计数。

我已尝试使用select expressions执行默认设置,但由于我的表尚未创建,因此我看起来无法从中创建选择表达式。

谢谢!

2 个答案:

答案 0 :(得分:1)

由于other answers

,我终于找到了可行的解决方案
class Foo(Model):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    date = Column(Date, default=datetime.now)
    reference = Column(Unicode)

@db.event.listens_for(Foo, 'before_insert')
def receive_before_insert(mapper, connection, foo):
    ref = foo.query.filter(db.and_(db.extract('month', Foo.date)==datetime.now().month,
                                           db.extract('year',  Foo.date)==datetime.now().year)
                                              ).count()
    foo.reference = 'FOO{year}{month}-{ref:03}'.format(year=datetime.now().year,
                                                       month=datetime.now().month,
                                                       ref=ref)
但是,我将问题保持开放,以防有人提出可能的建议 直接嵌入default密钥。

答案 1 :(得分:1)

以下是使用默认值而不是事件的方法:

def foo_reference_default(context):
    now = datetime.now()
    month, year = now.month, now.year
    ref = context.connection.execute(db.select([Foo.__table__]).where(
        db.and_(db.extract('month', Foo.date)==month,
                db.extract('year', Foo.date)==year)
    ).count()).scalar() + 1
    return u'FOO{year}{month}-{ref:03}'.format(year=year, month=month, ref=ref)


class Foo(Model):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    date = Column(Date, default=datetime.now)
    reference = Column(Unicode, default=foo_reference_default)

这与您的答案实际上相同:先完成SELECT以填充INSERT。 (请注意,我添加了+1,因此它将从001而不是000开始。)

当然,您可以使用lambda将函数嵌入到默认值中,但我不推荐它 - 您只想调用now()一次。多次调用它会导致在月份和年份边缘获得不一致数据的微小但真实的可能性。