如何在Django中创建一个记录一段时间后删除它?

sg24os4d  于 2023-07-01  发布在  Go
关注(0)|答案(3)|浏览(134)

我正在构建一个具有“故事功能”的应用程序,它与Instagram的故事功能非常相似,所以我想在创建24小时后删除一个故事。因此,如果故事是在2021年1月1日下午12:00创建的,我希望在2021年1月2日下午12:00自动删除它。我用的是django3.1
我的型号:

class Story(models.Model):
    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
    text = models.CharField(max_length=200)
    image = models.ImageField(blank=True, null=True)
    video = models.FielField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    expiration_time = models.DateTimeField()

我想删除每个记录后,他们的特定到期时间。
[过期时间在post_保存函数中设置]

tcbh2hod

tcbh2hod1#

最可靠的方法通常是过滤和删除每小时/每天/每周运行一次的任务中的项目的组合。
因此,我们可以检索尚未过期的项目:

from django.db.models.functions import Now

stories = Story.objects.filter(expiration_time__lt=Now())

如果您需要经常进行过滤,为此创建一个manager [Django-doc]可能会更有趣。

from django.db import models
from django.db.models.functions import Now

class StoryManager(models.Manager):

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(
            expiration_time__lt=Now()
        )

class Story(models.Model):
    # …
    xpiration_time = models.DateTimeField(db_index=True)
    
    objects = StoryManager()

**db_index=True**部分[Django-doc]通常会提高过滤过期对象的性能。

当然,这并不会删除元素,它只是不会检索这些元素(因此,如果您在视图中过滤这些元素,那么您将看不到这些元素)。
您可以创建一个周期性任务,例如cronjob [wiki],它将每天,每周,每月,每小时运行以删除元素。你可以通过定义一个 management command [Django-doc]来做到这一点:

# app_name/management/commands/remove_expired_stories.py

from django.core.management.base import BaseCommand
from django.db.models.functions import Now

from app_name.models import Story

class Command(BaseCommand):
    help = 'Remove expired stories'

    def handle(self, *args, **options):
        Story._base_manager.filter(expiration_time__gte=Now()).delete()

然后您可以手动运行:

python3 manage.py remove_expired_stories

也可以安排此任务定期运行。这是更强大的:如果由于某种原因调度程序不再工作,那么过滤仍然会阻止您看到过期的Story。这也比为每个故事安排到期脚本更简单和更有效,特别是因为如果到期时间稍后更改,则删除已安排的项目并重新安排这些项目将非常复杂。

8yparm6h

8yparm6h2#

我明白了,简单的解决方案往往比更漂亮、更复杂的解决方案更好。
如果这是我,我会运行一个预定的进程,每小时运行一次,检查SQL表中的每一行。然后,检查发布时间是否大于24小时前。
如果你真的想得到花式,我建议Redis在创建帖子时创建一个预定的进程。在24小时内安排一个删除该特定帖子的任务。

a64a0gku

a64a0gku3#

我想威廉·货车昂森是对的。。我是说他的方法

###LOGIC 

time A i.e Now()---------somwhere in the future -------------------------timeB i.e expiration_time
if time A > time B its expired 
if time A < time B its not expired

所以与

...
 expiration_time = models.DateTimeField(db_index= True,default=Now()+timedelta(days=1), editable = False)

在你的模型和你的经理

class StoryManager(models.Manager):

def get_queryset(self, *args, **kwargs):
    return super().get_queryset(*args, **kwargs).filter(
        expiration_time__gt=Now()
    )

然后在命令/.py中这个类Command(BaseCommand):help =“清除过期消息”

def handle(self, *args, **options):
    Story._base_manager.filter(expiration_time__lte=Now()).delete()

一切都会好的。

相关问题