在使用 Python Camelot 时,存储在数据库中的小时数是整数,以避免浮点数错误。例如,1 小时存储为 100,2.5 小时存储为 250,等等。但是在显示小时数时,希望将它除以 100.0。
解决方案
方法一
可以使用 @property 修饰符来创建一个属性,该属性的值是根据另一个属性计算出来的。例如:
@property
def total_hours_estimated (self):
value = sum([ work.hours_estimated for work in self.work ])
value = value / 100.0
return value
上面的代码会将工作中估计的小时数加起来,然后除以 100.0。需要注意的是,这种方法计算出的值只能在 Python 代码中使用,在 Camelot 表中无法对其进行排序。
方法二
使用 ColumnProperty 修饰符来创建一个列属性,该属性的值是根据一个 SQL 查询计算出来的。例如:
@ColumnProperty
def total_hours_estimated_colprop (self):
return sql.select( [sql.func.sum(Work.hours_estimated)],
Work.task_id == self.id)
上面的代码会创建一个名为 total_hours_estimated_colprop 的列属性,该属性的值是工作中估计的小时数之和。需要注意的是,这种方法计算出的值可以在 Camelot 表中排序,但需要在列属性中指定数据类型,例如:
class Task(Entity):
...
class Admin(EntityAdmin):
list_display = ['id', 'text', 'total_hours_estimated_colprop']
field_attributes = {
'total_hours_estimated_colprop': {'delegate':delegates.FloatDelegate',
'precision': 3} }
上面的代码会将 total_hours_estimated_colprop 列属性的显示类型设置为浮点数,精度为 3 位。
代码示例
以下是一个完整的代码示例,演示了如何使用 @property 和 ColumnProperty 修饰符来创建小时数属性:
from camelot.admin import EntityAdmin, delegates
from camelot.core import Entity, Column, sql
from datetime import date, datetime
from sqlalchemy import Integer, String, Boolean, Date, ForeignKey, relationship
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Task( Entity, Base ):
__tablename__ = 'task'
id = Column( Integer, primary_key=True )
text = Column( String, nullable=False )
completed = Column( Boolean, default=False )
date_created = Column( Date, default=datetime.today )
date_completed = Column( Date )
notes = Column( String )
@property
def total_hours_estimated (self):
value = sum([ work.hours_estimated for work in self.work ])
value = value / 100.0
return value
@ColumnProperty
def total_hours_estimated_colprop (self):
return sql.select( [sql.func.sum(Work.hours_estimated)],
Work.task_id == self.id)
class Work( Entity, Base ):
__tablename__ = 'work'
id = Column( Integer, primary_key=True )
date = Column( Date )
hours_estimated = Column( Integer, default=0 )
hours_actual = Column( Integer, default=0 )
task_id = Column( Integer, ForeignKey('task.id') )
task = relationship(Task, backref='work')
engine = create_engine('sqlite:///test.db')
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
task1 = Task(text='Task 1')
session.add(task1)
session.commit()
work1 = Work(date=date(2020, 1, 1), hours_estimated=100)
work2 = Work(date=date(2020, 1, 2), hours_estimated=200)
task1.work.append(work1)
task1.work.append(work2)
session.commit()
print(task1.total_hours_estimated) # 3.0
print(task1.total_hours_estimated_colprop) # 3.0
上面的代码首先创建了两个类,Task 和 Work,分别表示任务和工作。然后创建了一个数据库引擎和一个会话。接下来创建了一个任务,并向该任务添加了两项工作。最后,打印出任务的总估计小时数。