2016-05-14 1 views
0

J'ai configuré une API de repos avec DRF (Django Rest Framework). L'une des fonctions de l'API consiste à créer un compte utilisateur (registre a.k.a.). Une fois l'utilisateur "créé", j'envoie une tâche à céleri pour envoyer un email de confirmation.Créer un utilisateur lors de l'envoi d'une tâche à Celery me donner une erreur: La requête correspondante n'existe pas

Mais quand la tâche est exécutée par le travailleur de céleri, une erreur est survenue:

DoesNotExist: User matching query does not exist.

La tâche prend un nom d'utilisateur et rien de plus. Ensuite, j'essaie de faire un appel à la DB. Et c'est en ce moment qu'il échoue.

À ce moment précis, je suis à peu près sûr que l'utilisateur n'est pas créé dans la base de données car la méthode create() est terminée.

Si j'avais un sleep() dans ma tâche, cela fonctionne.

Ma question est la suivante:

Comment puis-je assurer que mon utilisateur est créé dans la base de données avant d'envoyer la tâche à Céleri?

J'utilise Django 1.9.x

MISE À JOUR 1

tasks.py

@shared_task(name='users.utils.send_activation_email') 
def send_activation_email(url, user_id): 
    try: 
     user = User.objects.get(id=user_id) 
     # ... 
    except User.DoesNotExist: 
     # handle exception 

serializers.py

def create(self, validated_data): 
    user_data = validated_data.pop('user') 
    user = User.objects.create(username=user_data['email'], email=user_data['email'], is_active=False) 
    user.set_password(user_data['password']) 
    user.save() 

    user_profile = user.profile 
    user_profile.language = get_language() or settings.LANGUAGE_CODE 
    user_profile.display_name = validated_data['display_name'] 
    user_profile.save() 
    user_profile.generate_activation_key() 

    request = self.context['request'] 
    url = request.build_absolute_uri(reverse('user_confirm', kwargs={'activation_key': user.profile.activation_key})) 
    send_activation_email.delay(url, user.id) # Celery task 
    subscribe_to_newsletter.delay(user.id, True) # Celery task 

    return user_profile 

MISE À JOUR 2

Après avoir examiné mes paramètres, j'ai trouvé ceci:

DATABASES = { 
    'default': { 
     'ENGINE': 'django.contrib.gis.db.backends.postgis', 
     'NAME': '*****', 
     'USER': '*****', 
     'PASSWORD': '*****', 
     'HOST': '*****', 
     'PORT': 5432, 
     'ATOMIC_REQUESTS': True, 
    } 
} 

I handicapés ATOMIC_REQUESTS et cela a fonctionné!

+0

Pas assez pour aller en mais je pense que vous avez des données UNCOMMITED au moment où la tâche de céleri est exécuté . Si vous n'êtes pas en mode de validation automatique, assurez-vous que la transaction est validée avant de passer la tâche à céleri. – e4c5

+0

Vous pouvez placer la partie enregistrement dans la tâche pour vous assurer que l'utilisateur est créé et que l'e-mail est envoyé en arrière-plan. S'il vous plaît noter que dans ce cas, vous devez valider les données (nom d'utilisateur étant unique ou autre) avant d'envoyer la tâche à céleri. –

+1

@ e4c5 c'est exactement ce qui s'est passé quand vous avez dit que j'avais des données non-validées. Après avoir examiné mon code, j'ai remarqué que j'ai mis ATOMIC_REQUESTS = True dans ma configuration de base de données. Après l'avoir enlevé, ça a marché comme un charme. – Kornikopic

Répondre

0

Utilisation du signal Django, django.db.models.signals.post_save qui envoie un signal au récepteur après une méthode de modèle save() est appelée

from django.contrib.auth.models import User 
from django.db.models.signal import post_save 

def create_user_callback(sender, **kwargs): 
    user = kwargs['instance'] 
    if kwargs['created']: 
     #send email to the user 

post_save.connect(create_user_callback, sender=User)