2011-11-12 5 views
8

Dans mon models.py:Django - L'exécution d'une tâche par le céleri d'un modèle

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) 

Dans mon 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 

Ce retourne les éléments suivants:

  • Type d'exception: ImportError
  • Exception Valeur: ne peut pas importer des tâches nom

L'erreur disparaît si je commente sur from core.models import Image dans tasks.py, mais cela va évidemment causer un problème puisque Image n'a pas de sens ici. J'ai essayé d'importer à l'intérieur create_thumbnail mais il ne reconnaîtra toujours pas Image.

J'ai lu quelque part qu'habituellement l'objet lui-même peut être passé comme argument à une tâche et cela résoudrait mon problème. Cependant, un ami m'a dit une fois qu'il est considéré comme la meilleure pratique d'envoyer le moins de données possible dans un message RabbitMQ, afin d'obtenir que j'essaie de ne transmettre que l'ID de l'image et ensuite le récupérer dans la tâche.

1) Est-ce que ce que j'essaie de faire est considéré comme une bonne pratique? Si oui, comment puis-je le résoudre?

2) J'ai remarqué dans tous les exemples que j'ai trouvés sur le web qu'ils exécutent la tâche depuis une vue et jamais depuis un modèle. J'essaie de créer une vignette chaque fois qu'une nouvelle image est téléchargée, je ne veux pas appeler create_thumbnail dans toutes les formes/vues que j'ai. Une idée à ce sujet? Est-ce que l'exécution d'une tâche à partir d'un modèle n'est pas recommandée ou une pratique courante?

Répondre

13

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

Oui, en passant seulement un peu d'information à la tâche est généralement une bonne chose comme vous l'avez mentionné.

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?

J'ai remarqué la même chose, et je sens que des tutoriels et des tâches d'appel de documentation de leur point de vue, car il est plus facile de démontrer comment les choses fonctionnent avec des vues simples que des modèles ou des formulaires.

Pour éliminer les importations circulaires, vous devez déterminer le mode d'importation. En général, tasks.py devra importer beaucoup de choses depuis models.py alors que models.py a rarement besoin de savoir quoi que ce soit sur tasks.py. La norme devrait être que models.py ne soit pas importé depuis tasks.py. Ainsi, si vous avez besoin de faire cela et appelez une tâche à partir d'une méthode de modèle, faire l'importation dans la méthode comme si:

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

J'ai vraiment apprécié le paragraphe" Pour éliminer les importations circulaires, vous devriez réfléchir à la manière dont les importations devraient se produire ... ". Je vous remercie. – pawelmech

1

Je me demande si le problème pourrait être une importation circulaire (models et tasks en s'important au niveau supérieur). essayez de déplacer « from core.models import Image » dans create_thumbnail, à savoir le changement 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 
+0

suivant, je l'ai déjà essayé, dans ce cas, le message est envoyé correctement mais create_thumbnail génère une erreur: 'Fichier « /home/ubuntu/project/core/tasks.py », ligne 5, dans create_thumbnail' 'de core.models importer Image' ' NameError: nom global 'Image' n'est pas défini' – abstractpaper

+0

Je présume que 'core' est le nom de votre application. avez-vous essayé de préfixer le nom du projet (c'est-à-dire 'from project.app.models import Model')? django fait du chemin magique qui est parfois moins que utile – second

+0

Juste fait, la même erreur est retournée: 'NameError: le nom global 'Image' n'est pas défini'. J'ai déjà ajouté mon projet dans 'django.wsgi'. – abstractpaper

4

Vous n'avez pas besoin d'importer la tâche elle-même.Essayez d'utiliser le

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) 
+1

celery.execute ne semble plus exister dans le céleri 3.x – Titusz

Questions connexes