Python 如何使用django后台任务

Python 如何使用django后台任务,python,django,background-task,Python,Django,Background Task,我正在申请django。为了根据行和注释计算提要的排名,我尝试使用django后台任务。我在节点模型中使用的功能是: @background(schedule=60) def get_score(self): p = self.likes+self.comments # popularity t = (now()-self.date).total_seconds()/3600 # age_in_hrs # last_acti

我正在申请django。为了根据行和注释计算提要的排名,我尝试使用django后台任务。我在节点模型中使用的功能是:

    @background(schedule=60)
    def get_score(self):
        p = self.likes+self.comments    # popularity
        t = (now()-self.date).total_seconds()/3600  # age_in_hrs
        # last_activity =
        n = self.admin_score
        score = (p/pow((t+1), 1.2))*n
        self.score = score
        return score

但我看不到分数有任何变化。这意味着我正在以一种正确的方式做这件事,我缺少了基本的概念。有人能告诉我如何使用django后台任务来安排任务或让我参考一些现有的文档吗。

您应该按照描述运行
python manage.py process\u tasks
。您可以将其添加到crontab以定期执行

UPD:

  • 您不需要使用crontab运行
    process\u tasks
    ,因为此命令每5秒在内部休眠一次(此值可配置),然后再次检查是否有任何任务要运行
  • 你的任务看起来很奇怪。您应该在单独的文件中将其声明为全局函数,并在其中传递模型的
    id
    ,通过
    id
    获取对象并进行计算并保存您的对象

  • 你似乎用错了方法

    假设您必须执行某些特定任务,例如,在用户注册后5分钟发送邮件。所以你要做的是:

    使用django后台任务创建任务

    @background(schedule=60*5)
    def send_html_mail_post(id, template):
        u = User.objects.get(id=id)
        user_email = u.email
        subject = "anything"
        html_content = template.format(arguments)
        from_email, to = from_email, user_email
        text_content = ''
        msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
        msg.attach_alternative(html_content, "text/html")
        msg.send()
    
    顶部的decorator定义调用函数后实际事件发生的时间

    需要的时候打电话

    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            up = UserProfile.objects.create(user=instance)
            up.save()
            tasks.send_welcome_email(up.user.id, template=template)
    
    这将创建任务并将其保存在数据库中,还将执行任务的时间存储在db中

    您想要做的事情,定期做一些事情,可以通过创建cron作业更容易地完成


    您要做的是,创建一个函数,如问题中所示。然后定义一个cron作业,每5分钟或任意间隔调用一次。

    django后台任务和django后台任务之间有区别。
    django后台任务未维护,与较新的django版本不兼容。不久前,我们使用新功能对其进行了更新和扩展,并在上维护了新的向后兼容包django background tasks。新的django background tasks应用程序可以从下载或安装。

    因为这个问题似乎很一般,我相信根据我的个人经验,这是关于“如何使用django background tasks”的快速备忘单的正确位置。希望我不是唯一一个使用它的人:)

    环境
    • Python 3.8
    • Django 3.1
    装置 我喜欢这样:

    现在将“后台任务”添加到settings.py中已安装的应用程序:

    并执行数据库迁移,以确保django后台任务架构就位:

    > pipenv shell
    (my-django-project) bash-3.2$  python manage.py migrate
    
    创建和注册任务 任何Python函数都可以是一项任务,我们只需应用@background注释即可注册它:

    from background_task import background
    
    @background(schedule=10)
    def do_something(s1: str, s1: str) -> None:
       """
       Does something that takes a long time
       :param p1: first parameter
       :param p2: second parameter
       :return: None
       """
       pass
    
    现在我们可以在项目中像往常一样调用函数:

    do_something("first parameter", "second parameter")
    
    需要注意的是,调用函数并不实际执行其代码;相反,任务记录由“django background tasks”模块存储到数据库中,更准确地说是存储到“background_Task”表中。因此,编写一个返回某些内容的任务函数没有什么用处,因为该任务稍后将在后台执行,因此调用该函数时返回的“值”几乎没有意义。我看到的返回值的唯一用例是出于测试目的,请参阅下面的测试任务部分

    处理任务 为了实际运行已注册的任务,我们必须使用以下管理命令:

    > python manage.py process_tasks
    
    有关命令选项的说明,请参阅。 正如其他用户已经指出的,通常将此命令包装在cron作业中,以确保定期处理任务。在这种情况下,duration选项可能很有用:它表示process_task命令保持运行的秒数。默认情况下,持续时间为0,这意味着“永远运行”,但在我看来,这是相当危险的,因为如果由于某种原因命令崩溃或中断,您的任务将不再被处理,并且可能需要很长时间才能实现

    更好的方法是将持续时间设置为定义良好的时间,例如15分钟,然后将cron作业配置为每15分钟运行一次,以重新启动处理命令。这样,如果命令崩溃,它将在稍后由cron作业重新启动

    测试任务 通过“process_tasks”管理命令测试任务很糟糕,我们应该坚持使用Python模块,这也是“Django方式”

    当然,我不会在这篇文章中讨论unittest,我只想指出,在单元测试期间,您希望以同步方式执行函数,就像普通Python函数一样。其语法如下所示:

    do_something.now("first parameter", "second parameter")
    
    修饰符“now”运行函数并等待其终止。在我看来,这是返回值有用的唯一用例。有了返回值,您就可以使用unittest提供的“assert*”函数的全部功能

    检查任务是否已在运行 有时,您可能不希望同一任务运行多次。例如,我经常使用背景任务来训练机器学习模型,这需要很多时间。为了防止我的数据被弄乱,我更喜欢确保在上一个训练任务完成之前,不能在同一个模型上启动另一个训练任务

    为了让它工作,我必须在开始新任务之前检查任务是否已经在运行;但是如何唯一地识别任务呢?对我来说,简单的方法是为任务分配一个“详细名称”,这可以在计划任务时完成:

    do_something("first parameter", "second parameter", verbose_name="my_task_verbose_name")
    
    现在,如果我想检查这个任务是否已经在运行,我可以简单地读取background_task表并验证没有任务
    do_something.now("first parameter", "second parameter")
    
    do_something("first parameter", "second parameter", verbose_name="my_task_verbose_name")
    
    from background_task.models import Task
    
    tasks = Task.objects.filter(verbose_name="my_task_verbose_name")
    if len(tasks) == 0:
        # no task running with this name, go ahead!
        pass
    else:
        # task already running
        pass