Disclaimer 1:Trước hết, nghĩ rằng nếu nó không phải là "rẻ hơn" thực sự sử dụng postgresql
thay vì sqlite ở khắp mọi nơi. Tôi cho rằng bạn có sự khác biệt về phát triển/sản xuất, mà bạn nên tránh. Cài đặt postgresql
trên bất kỳ hệ điều hành hiện đại nào là khá tầm thường.
Giả sử ở trên không phải là một tùy chọn/mong muốn, hãy tiếp tục.
Tuyên bố từ chối trách nhiệm 2: Giải pháp với cấu trúc SQL tùy chỉnh (theo câu trả lời của @ Josh) thực sự là cách hợp lý duy nhất để đạt được điều này. Thật không may, giải pháp được đề xuất không thực sự hoạt động cho sqlite
và không thể khắc phục được chỉ với một vài dòng, do đó có một câu trả lời riêng biệt.
Giải pháp: Giả sử bạn có mô hình sau:
class Appointment(Base):
__tablename__ = 'appointment'
id = Column(Integer, primary_key=True)
name = Column(String(255))
datetime = Column(DateTime) # @note: should be better named `start_date`?
duration = Column(Integer)
sqlite
là thực sự khó khăn đối phó với hoạt động ngày, đặc biệt là thêm/trừ khoảng thời gian từ ngày. Vì vậy, chúng ta hãy tiếp cận nó một chút khác nhau và tạo ra các chức năng tùy chỉnh để có được một khoảng thời gian giữa hai thời điểm trong vài phút:
class diff_minutes(expression.FunctionElement):
type = Integer()
name = 'diff_minutes'
@compiles(diff_minutes, 'sqlite')
def sqlite_diff_minutes(element, compiler, **kw):
dt1, dt2 = list(element.clauses)
return compiler.process(
(func.strftime('%s', dt1) - func.strftime('%s', dt2))/60
)
@compiles(diff_minutes, 'postgresql')
def postgres_diff_minutes(element, compiler, **kw):
dt1, dt2 = list(element.clauses)
return compiler.process(func.extract('epoch', dt1 - dt2)/60)
Bạn đã có thể thực hiện kiểm tra bằng cách sử dụng truy vấn sau đây (tôi không thêm limit(1).one_or_none
trong các ví dụ của tôi, mà bạn rõ ràng có thể làm khi bạn cần nó):
q = (
session
.query(Appointment)
.filter(Appointment.datetime <= func.now())
.filter(diff_minutes(func.now(), Appointment.datetime) <= Appointment.duration)
)
Nhưng bây giờ bạn không bị giới hạn bởi thời gian hiện tại (func.now()
), và bạn có thể kiểm tra (và kiểm tra đơn vị) dữ liệu của bạn chống lại bất cứ lúc nào:
012.
# at_time = func.now()
at_time = datetime.datetime(2017, 11, 11, 17, 50, 0)
q = (
session
.query(Appointment)
.filter(Appointment.datetime <= at_time)
.filter(diff_minutes(at_time, Appointment.datetime) <= Appointment.duration)
)
Về cơ bản, sự cố được giải quyết tại đây và giải pháp sẽ hoạt động cho cả hai công cụ cơ sở dữ liệu mà bạn sử dụng.
BONUS:
Bạn có thể ẩn việc thực hiện kiểm tra nếu sự kiện là hiện tại sử dụng Hybrid Methods.
Cho phép thêm sau vào lớp Appointment
:
@hybrid_method
def is_current(self, at_time=None):
if at_time is None:
at_time = datetime.datetime.now()
return self.datetime <= at_time <= self.datetime + datetime.timedelta(minutes=self.duration)
@is_current.expression
def is_current(cls, at_time=None):
if at_time is None:
at_time = datetime.datetime.now()
stime = cls.datetime
diffm = diff_minutes(at_time, cls.datetime)
return and_(diffm >= 0, cls.duration >= diffm).label('is_current')
Người đầu tiên cho phép bạn chạy kiểm tra trong bộ nhớ (trên python, không nằm về phía SQL):
print(my_appointment.is_current())
thứ hai cho phép bạn tạo truy vấn như dưới đây:
q = session.query(Appointment).filter(Appointment.is_current(at_time))
nơi nếu at_time
nó không được chỉ định, thời gian hiện tại sẽ được sử dụng. Tất nhiên, bạn có thể sửa đổi truy vấn theo ý muốn:
current_appointment = session.query(Appointment).filter(Appointment.is_current()).limit(1).one_or_none()
Trong ví dụ của bạn, bạn không bị đảo ngược logic? Như trong: là 'Appointment.datetime' giữa * [now, now + duration] *. Ngoài ra, là 'TIMESTAMPADD' ngay cả một hàm trong Postgresql? –