在视图中的模型中保存文件有效,但在 Celery 任务中无效

Posted

技术标签:

【中文标题】在视图中的模型中保存文件有效,但在 Celery 任务中无效【英文标题】:Saving File in Model in View works but not in Celery Task 【发布时间】:2021-09-07 10:30:54 【问题描述】:

我遇到了这种非常奇怪的行为,当我在视图中保存新模型实例时,分配的文件被保存,但是当我在 Celery 中这样做时,实例被保存,而不是文件。

这些是我的观点(缩短):

def post(self, request, *args, **kwargs):
    [...]
    html = render_to_string('pdf/w_html.html', 'request': self.object)
    out = BytesIO()
    HTML(string=html).write_pdf(out, stylesheets=[CSS(settings.STATIC_ROOT + "/css/pdf.css"), 
                                                  'https://fonts.googleapis.com/css2?family=Montserrat&family=Playfair+Display&display=swap'])
    document = Document(product=product, document_type=4,
                        language=1, date=timezone.now().date(),
                        file=File(out, name='Best_Execution_Report.pdf'))
    document.save()

其中 self.object 是一个 Request 实例。 上面的代码正是它应该做的(即保存模型和生成的pdf)。

但是一旦我像这样修改上面的代码:

def post(self, request, *args, **kwargs):
    [...]
    generate_best_execution_report.apply_async(kwargs='request_id': self.object.pk)

使用以下 celery 任务:

@shared_task
def generate_best_execution_report(request_id):
    """Task to automatically generate best execution Reports and save it to the Documents Model (of the product app)."""
    request_obj = Request.objects.get(pk=request_id)
    logger.info(request_obj)
    html = render_to_string('pdf/w_html.html', 'request': request_obj)
    logger.info(html)
    out = BytesIO()
    HTML(string=html).write_pdf(out,
                                stylesheets=[
                                    CSS(settings.STATIC_ROOT + "/css/pdf.css"),
                                    'https://fonts.googleapis.com/css2?family=Montserrat&family=Playfair+Display&display=swap'
                                ]
                                )

    logger.info(out)
    with transaction.atomic():
        document = Document(product=request_obj.product, document_type=4,
                            language=1, date=timezone.now().date(),
                            file=File(out, name='Best_Execution_Report.pdf'))
        try:
            document.save()
        except Exception as e:
            logger.info(e)

    logger.info(document)
    return True

(请注意,请求是产品上的一对一关系,所以我必须稍微改变一下 Document 实例的生成方式)

实例将被保存(文档的路径也是正确的!没有抛出异常),但文件本身不会被保存。

我错过了什么??

【问题讨论】:

【参考方案1】:

我发现了问题。整个应用程序在 Docker 环境中运行。 Django 应用程序和 Celery 已在单独的容器中运行。问题是 Celery 无法访问 Django 文件系统,因此文件被保存,但无法访问 Django 容器……非常愚蠢的错误,但我花了几天时间才弄清楚。因此,如果有人偶然发现同样的问题,请检查您的 docker 卷。

【讨论】:

以上是关于在视图中的模型中保存文件有效,但在 Celery 任务中无效的主要内容,如果未能解决你的问题,请参考以下文章

Django 模型没有保存到 Celery Task 中的数据库中

模型方法在 Bookings 模型中有效,但在事件和票证中无效

Django post_save 信号和 celery 任务之间可能的竞争条件

为啥我的异步代码在控制器中有效,但在模型中无效?

在 Qt 模型/视图中修改数据表示

将模型中的DateTime格式化为仅在视图中的日期