如何在Django中使用Celery从request.FILES上传文件?

huangapple go评论59阅读模式
英文:

How to upload a file from request.FILES using Celery in Django?

问题

有一个名为Post的模型,其中包含一个图像字段。图像字段从表单中获取其值。我不想将媒体文件存储在本地。因此,我正在使用S3Boto3Storage作为我的文件存储方式。有没有办法使用Celery保存Post模型对象(以便通过Celery上传图像文件,以减少用户等待时间)。我尝试编写一个Celery任务来保存对象。但显然不能将文件作为参数直接发送给Celery。以下是我的代码:

views.py:

tasks.upload_image_task.delay(
    user_pk,
    post_body,
    request.FILES.get("image"),
)

tasks.py:

@shared_task
def upload_image_task(user_pk, body, image):
    user = User.objects.get(pk=user_pk)
    post = Post.objects.create(user=user, body=body, image=image, post_type="IMG")
    post.save()

这将导致Object of type InMemoryUploadedFile is not JSON serializable错误。
我还读到可以首先将文件保存在本地,然后使用任务上传文件。但我想直接上传它。

英文:

There's a model called Post which has an image field. The image field gets its value from a form. I don't want media files to be stored locally. So I'm using S3Boto3Storage as my file storage. Is there a way to save the Post model object using celery (so that the image file gets uploaded by celery to not keep the user waiting). I tried writing a celery task to save the object. But apparently you can't just send a file to Celery as a parameter. This is what I have so far:

views.py:

tasks.upload_image_task.delay(
    user_pk,
    post_body,
    request.FILES.get("image"),
)

tasks.py:

@shared_task
def upload_image_task(user_pk, body, image):
    user = User.objects.get(pk=user_pk)
    post = Post.objects.create(user=user, body=body, image=image, post_type="IMG")
    post.save()

This will result in Object of type InMemoryUploadedFile is not JSON serializable.
I also read that first you can save the file on local and then upload the file using a task. But I want to upload it directly.

答案1

得分: 1

Amazon S3有一个预签名的上传URL的概念,您可以使用它直接从用户浏览器上传照片,而不是从您的Django后端上传。这可以使您的API更快,但您仍然需要等待文件在浏览器上传。

但是,如果出于其他原因,您仍然希望将图像提交到后端,除非您有一个可以从Celery工作进程和Django进程都访问的通用文件存储,否则您不能使用Celery。在这种情况下,您可以首先将文件保存在本地,然后将路径发送给Celery任务的输入参数。但如果您没有这样的存储,您可以在发送响应后异步运行文件上传。您可以在这里找到相关的答案。

英文:

Amazon S3 has a concept of presigned post url, which you can use to directly upload the photo from the user browser instead of uploading it from your django backend. That should make your API faster but you still have to wait while the file is uploaded on the browser.

But for other reasons if you still want to post image to the backend, you cannot be using celery unless you have common file storage accessible from both celery worker and django process. In that case, you can first save the file locally and send the path to celery task input arguments. But if you don't have such storage, you can run the uploading of file asynchronously after sending the response. You can find answers regarding that here.

huangapple
  • 本文由 发表于 2023年7月23日 20:33:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76748255.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定