【问题标题】:Django: how to return a view THEN execute wind-down code? [closed]Django:如何返回视图然后执行结束代码? [关闭]
【发布时间】:2020-09-11 01:42:51
【问题描述】:

我想知道在 Django 中是否有规范的方法?

本质上视图的结构方式是,它们是返回结果的函数,该结果传递给客户端。可以这么简单:

from django.http import HttpResponse

def my_view(request):
    return HttpResponse('This is my view!')

但是让我们假设当 my_view 被加载时,里面有一些肉:

from django.http import HttpResponse

def my_view(request):
    result = do_stuff()
    return HttpResponse(result)

do_stuff 有一些适度耗时的结束代码来运行,即结果不依赖于的代码,但它会以同样的方式运行(也许是为了释放资源,将一些东西返回到清洁状态等无关紧要,原则是do_stuff 有一些要运行的代码,它有点慢,因此运行它会延迟结果的传递,但结果绝不取决于它,所以它宁愿返回结果然后运行这段代码。

在一个荒谬的想象和荒谬的世界中,这可能类似于:

from django.http import HttpResponse

def my_view(request):
    result = do_stuff()
    return HttpResponse(result)
    do_more_stuff()

当然,do_more_stuff 永远不会在现实世界中运行,因为返回的本质。

现在我可以想象这里的解决方案将do_more_stuff() 转至后台线程或转入子进程以完成允许 my_view 返回。

我问的原因有两个:

  1. 关于这样一个分离的进程线程的生命周期,我可以费力地测试或深入研究一个轻微的谜团,但其他人可能已经掌握了。是否保证运行完成(假设运行时间适中,而不是像挂起、死锁或长达一个月的运行时间这样的特殊情况......但这是一个普通的结束过程,但可能需要 1-5 秒的实时时间和延迟这么长时间的视图交付在页面视图延迟中是非常明显的)。我的意思是视图函数是在一个进程中运行的,因此存在关于该进程的生命周期以及它产生的任何线程或子进程的问题。我有点想象如果 Django 在 uwsgi 下运行说视图没有被处理是很健壮的短暂的进程,但在那些徘徊并继续处理视图的进程中,因此长期存在,任何合理的后台线程或子进程都将能够轻松完成。

  2. 也许有一种规范的 Django 方法可以做到这一点。我很好奇,因为我不可能是第一个或唯一一个满足这种需求的人(即在一个减慢交付但不依赖于响应的视图中找到代码)并且它必须是开发人员遇到的相当普遍的事情,并且可能有一个我没有找到的规范解决方案。我检查了中间件选项,但它同样受到限制,即就像视图返回响应一样。

我怀疑解决方案可能存在于 request-finished 信号中:

https://docs.djangoproject.com/en/3.0/ref/signals/#request-finished

并且挂钩到该信号的函数在响应传递后运行并且不会延迟响应的传递。但是我不知道又没有测试它,所以很高兴输入(当我跑去测试它时;-)。

【问题讨论】:

  • 你会想要使用像芹菜这样的任务队列docs.celeryproject.org/en/stable/django/…
  • 如果社区投票,社区投票和三票显然关闭了这个问题,因为它是基于意见的,无法用事实回答。我只能建议向 Django 专家社区询问规范方法可以说是在任何一个阵营中(事实上可以回答,有或没有规范方法或可以用意见回答,因为没有,这就是我的d 建议做)。关于规范方法的事情是它出现在(Django 文档的)规范中。我还没有找到一个。但怀疑可能埋在某个地方。

标签: python django


【解决方案1】:

信号可能会为您解决问题,尽管您无法访问请求的详细信息(发送者 arg 只是类,而不是请求)。

您还可以扩展响应类:Execute code in Django after response has been sent to the client

最后,如果您确实想在单独的进程中运行,请考虑使用分布式任务队列,例如 celery (https://docs.celeryproject.org/en/stable/)

【讨论】:

  • 现在很讽刺的是,我已经在广泛使用 Celery,而我实际上特别想在客户端(Celery 客户端-工作者关系)而不是在工作人员中运行有问题的代码。一直在看信号。唉,它没有提供关于请求是什么的线索,并且是通用的,并且在每次请求后都会触发,所以它的上下文中没有足够的信息来决定是否运行有问题的视图以及它的结束代码是否应该运行。
  • 你不做工人的动机是什么?
  • 与这个问题并不真正相关,因为我很好奇,但动机是多方面的(我现在在工人中做了很多事情)并且与希望保持此代码无关工人的变幻莫测(可用性排队,上下文 - 例如,轻松访问请求数据表单数据等等)。我的意思不是我不能在工人(Celery Rocks)中做到这一点,而是我非常热衷于保留此代码客户端,并且好奇这些选项是对还是错。甚至可能使用工人是最好的方法。但我仍然对其他方法感到好奇。
  • 很公平。这看起来是一个非常聪明的选择。扩展响应类型:stackoverflow.com/questions/4313508/…
  • 哇,我非常努力地寻找现有的线程,但没有找到。很好的发现!
猜你喜欢
  • 2015-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
相关资源
最近更新 更多