Django - 通过模型中的 celery 执行任务

发布于 2024-12-15 04:43:19 字数 1231 浏览 2 评论 0原文

在我的 models.py 中:

from django.db import models
from core import tasks

class Image(models.Model):
    image     = models.ImageField(upload_to='images/orig')
    thumbnail = models.ImageField(upload_to='images/thumbnails', editable=False)

    def save(self, *args, **kwargs):
       super(Image, self).save(*args, **kwargs)
       tasks.create_thumbnail.delay(self.id)

在我的tasks.py 中:

from celery.decorators import task
from core.models import Image

@task()
def create_thumbnail(image_id):
    ImageObj = Image.objects.get(id=image_id)
    # other stuff here

这将返回以下内容:

  • 异常类型: ImportError
  • 异常值: 无法导入名称任务

如果我注释掉,错误就会消失tasks.py 中的 from core.models import Image ,但这显然会导致问题,因为 Image 在这里没有任何意义。我尝试将其导入 create_thumbnail 内,但它仍然无法识别 Image

我在某处读到,通常对象本身可以作为参数传递给任务,这可以解决我的问题。然而,一位朋友曾经告诉我,在 RabbitMQ 消息中发送尽可能少的数据被认为是最佳实践,因此为了实现这一目标,我尝试仅传递图像 ID,然后在任务中再次检索它。

1)我正在尝试做的事情被认为是最佳实践吗?如果是,我该如何解决?

2)我注意到在网上找到的所有示例中,它们都是从视图而不是模型执行任务。我试图在上传新图像时创建缩略图,我不想在我拥有的每个表单/视图中调用 create_thumbnail 。对此有什么想法吗?不建议从模型执行任务还是常见做法?

In my models.py:

from django.db import models
from core import tasks

class Image(models.Model):
    image     = models.ImageField(upload_to='images/orig')
    thumbnail = models.ImageField(upload_to='images/thumbnails', editable=False)

    def save(self, *args, **kwargs):
       super(Image, self).save(*args, **kwargs)
       tasks.create_thumbnail.delay(self.id)

In my tasks.py:

from celery.decorators import task
from core.models import Image

@task()
def create_thumbnail(image_id):
    ImageObj = Image.objects.get(id=image_id)
    # other stuff here

This is returning the following:

  • Exception Type: ImportError
  • Exception Value: cannot import name tasks

The error disappears if I comment out from core.models import Image in tasks.py, however this obviously will cause a problem since Image has no meaning in here. I have tried to import it inside create_thumbnail however it still won't recognize Image.

I have read somewhere that usually the object itself can be passed as an argument to a task and that would solve my problem. However, a friend once told me that it is considered best practice to send as little data as possible in a RabbitMQ message, so to achieve that I'm trying to only pass the image ID and then retrieve it again in the task.

1) Is what I'm trying to do considered a best practice? If yes, how do I work it out?

2) I have noticed in all the examples I found around the web, they execute the task from a view and never from a model. I'm trying to create a thumbnail whenever a new image is uploaded, I don't want to call create_thumbnail in every form/view I have. Any idea about that? Is executing a task from a model not recommended or a common practice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撑一把青伞 2024-12-22 04:43:19

1)我正在尝试做的事情被认为是最佳实践吗?如果是,我该如何解决?

是的,就像您提到的那样,仅向任务传递少量信息通常是一件好事。

2)我注意到在网上找到的所有示例中,它们都是从视图而不是模型执行任务。我试图在上传新图像时创建缩略图,我不想在我拥有的每个表单/视图中调用 create_thumbnail 。对此有什么想法吗?不建议从模型执行任务还是常见做法?

我注意到了同样的事情,并且觉得教程和文档从他们的视图中调用任务,因为使用简单的视图比使用模型或表单更容易演示事物如何工作。

为了消除循环导入,您应该考虑应该以哪种方式导入。通常,tasks.py 需要从 models.py 导入许多内容,而 models.py 很少需要了解有关tasks.py 的任何信息。标准应该是models.py不从tasks.py导入。因此,如果您确实需要执行此操作并从模型方法调用任务,请按如下方式在方法中进行导入:

from django.db import models

class Image(models.Model):
    image     = models.ImageField(upload_to='images/orig')
    thumbnail = models.ImageField(upload_to='images/thumbnails', editable=False)

    def save(self, *args, **kwargs):
       super(Image, self).save(*args, **kwargs)
       from core.tasks import create_thumbnail
       create_thumbnail.delay(self.id)

1) Is what I'm trying to do considered a best practice? If yes, how do I work it out?

Yes, passing only a little information to the task is generally a good thing like you mentioned.

2) I have noticed in all the examples I found around the web, they execute the task from a view and never from a model. I'm trying to create a thumbnail whenever a new image is uploaded, I don't want to call create_thumbnail in every form/view I have. Any idea about that? Is executing a task from a model not recommended or a common practice?

I've noticed the same thing, and feel that tutorials and documentation call tasks from their views because it is easier to demonstrate how things work using simple views than with models or forms.

To eliminate circular imports, you should think about which way the imports should happen. Generally, tasks.py will need to import many things from models.py whereas models.py rarely needs to know anything about tasks.py. The standard should be that models.py does not import from tasks.py. Thus, if you do need to do this and are calling a task from a model method, make the import in the method as so:

from django.db import models

class Image(models.Model):
    image     = models.ImageField(upload_to='images/orig')
    thumbnail = models.ImageField(upload_to='images/thumbnails', editable=False)

    def save(self, *args, **kwargs):
       super(Image, self).save(*args, **kwargs)
       from core.tasks import create_thumbnail
       create_thumbnail.delay(self.id)
且行且努力 2024-12-22 04:43:19

您不需要导入任务本身。尝试使用以下内容

from django.db import models
from celery.execute import send_task, delay_task

class Image(models.Model):
    image     = models.ImageField(upload_to='images/orig')
    thumbnail = models.ImageField(upload_to='images/thumbnails', editable=False)

    def save(self, *args, **kwargs):
       super(Image, self).save(*args, **kwargs)
       result = delay_task("task_prefix.create_thumbnail", post.id)

You don't need to import the task itself. Try using the following

from django.db import models
from celery.execute import send_task, delay_task

class Image(models.Model):
    image     = models.ImageField(upload_to='images/orig')
    thumbnail = models.ImageField(upload_to='images/thumbnails', editable=False)

    def save(self, *args, **kwargs):
       super(Image, self).save(*args, **kwargs)
       result = delay_task("task_prefix.create_thumbnail", post.id)
谈场末日恋爱 2024-12-22 04:43:19

我想知道问题是否可能是循环导入(模型和任务在顶层相互导入)。尝试将“from core.models import Image”移动到create_thumbnail,即将tasks更改为

from celery.decorators import task

@task()
def create_thumbnail(image_id):
    from core.models import Image
    ImageObj = Image.objects.get(id=image_id)
    # other stuff here

i wonder if the problem might be a circular import (models and tasks importing each other at the top level). try moving "from core.models import Image" into create_thumbnail, i.e. changing tasks to

from celery.decorators import task

@task()
def create_thumbnail(image_id):
    from core.models import Image
    ImageObj = Image.objects.get(id=image_id)
    # other stuff here
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文