删除特定资源的行的最佳方法是什么?

问题描述 投票:0回答:1

我正在使用Flask,Flask-Restful和Flask-sqlAlchemy进行简单的休息api,其中我有一个用户资源和一个项目资源。用户资源是Item资源的父资源。

那是

获取https://example.com/users/1/items以获得所有项目资源

我想自动删除每个月后的所有项目。问题是如何跟踪月末?

我做了一些研究,发现了python日期时间和日历库。

下面的代码是我如何获得用户注册的当天月末,然后我可以计算一年中月份的开始和结束日期的剩余时间并将其保存在数据库中。但现在我必须每次检查datetime.datetime.today(),然后检查开始和结束日期并删除特定用户下的项目资源。每次检查datetime.datetime.today()是否有效,如果等于结束日期,那么删除所有项目资源?

这就是我如何计算开始和结束日期

import datetime
import calendar

today = datetime.datetime.today()



days_in_current_month = calendar.monthrange(today.year, today.month)[1]

days_till_this_month_end = days_in_current_month -today.day

start_date = today + datetime.timedelta(days = days_till_this_month_end +1)
end_date = start_date

while some_condition:
    # details of the condision

days_in_current_month = calendar.monthrange(end_date.year, end_date.month)[1]

end_date  = end_date + datetime.timedelta(days = days_till_this_month_end +1)

这是我的UserModel:

class UserModel(db.Model):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key = True)
    firstname = db.Column(db.String(80))
    lastname = db.Column(db.String(80))
    email = db.Column(db.String(255))
    password = db.Column(db.String())
    items = db.relationship('ItemModel', lazy = "dynamic")

这是我的ItemModel:

class ItemModel(db.Model):
    __tablename__ = "categories"

    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(255))
    date = db.Column(db.DateTime, default=datetime.utcnow)

    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))

    user = db.relationship('UserModel')

最后删除我可以执行以下操作的项目:

@staticmethod
def delete_from_db():
    ItemModel.query.filter(start_date <= end_date).delete()
    db.session.commit()
python sqlalchemy flask-sqlalchemy flask-restful
1个回答
2
投票

您的ItemModel查询过滤器未指定任何列; start_date <= end_date表达式始终是True(因为end_date值总是比你的start_date更晚)。你也使问题过于复杂。

您所要做的就是在当前月份开始之前删除所有行。数据库将从那里获取它。本月的开始通过以下方式简单地确定:

import datetime

today = datetime.date.today()
month_start = today.replace(day=1)  # set day of the month to 1

ItemModel.query.filter(ItemModel.date < month_start).delete()

在每个查询上运行它足够便宜,特别是如果ItemModel.date列被索引。

如果您要定位特定数据库,则还可以使用数据库的日期函数。例如,Postgresql有一个方便的date_trunc() function,可用于指定要删除的行:

ItemModel.query.filter(
    ItemModel.date < func.date_trunc('month', func.current_date())
).delete()

这使用PostgreSQL CURRENT_DATE value,将其截断到当前月份(将日期的日期设置为1),然后删除当前月份之前的所有行。

如果您觉得这些删除查询的成本太高而无法在每个请求上运行,请考虑创建table view表的items,并在SQLAlchemy模型中使用该视图。然后,视图查询仅显示当前月份的项目:

CREATE OR REPLACE current_items WITH
SELECT * FROM items
WHERE items.date >= date_trunc(CURRENT_DATE, 'month')

并使用current_items作为表名来支持你的ItemModel对象,并有一个单独的批处理进程删除items表中较旧的任何行,以保持数据库清洁。这样,您的SQLAlchemy查询只能查看当前月份中的项目,并且每次批处理过程中删除这些行时都会删除一次。

您也可以使用SQLAlchemy通过事件挂钩自动应用过滤器,而不是视图。这是一个filtered query implementation

@event.listens_for(Query, "before_compile", retval=True)
def before_itemmodel_compile(query):
    """Limit all ItemModel queries to the current month"""
    if query._execution_options.get("include_all", False):
        return query

    for ent in query.column_descriptions:
        entity = ent['entity']
        if entity is None:
            continue
        insp = inspect(ent['entity'])
        mapper = getattr(insp, 'mapper', None)
        if mapper and mapper.class_ is ItemModel:
            today = datetime.date.today()
            month_start = today.replace(day=1)  # set day of the month to 1
            query = query.enable_assertions(False).filter(
                ent['entity'].date >= month_start)

    return query
© www.soinside.com 2019 - 2024. All rights reserved.