2013-04-25 4 views
11

Sto costruendo un sito web usando Python Flask. Tutto sta andando bene e ora sto cercando di implementare il sedano.Python Flask con sedano fuori dal contesto applicativo

Stava andando bene anche fino a quando non ho provato a inviare un'e-mail usando la fiaschetta di sedano. Ora sto ottenendo un errore di "lavorare fuori dal contesto dell'applicazione".

piena traceback è

Traceback (most recent call last): 
    File "/usr/lib/python2.7/site-packages/celery/task/trace.py", line 228, in trace_task 
    R = retval = fun(*args, **kwargs) 
    File "/usr/lib/python2.7/site-packages/celery/task/trace.py", line 415, in __protected_call__ 
    return self.run(*args, **kwargs) 
    File "/home/ryan/www/CG-Website/src/util/mail.py", line 28, in send_forgot_email 
    msg = Message("Recover your Crusade Gaming Account") 
    File "/usr/lib/python2.7/site-packages/flask_mail.py", line 178, in __init__ 
    sender = current_app.config.get("DEFAULT_MAIL_SENDER") 
    File "/usr/lib/python2.7/site-packages/werkzeug/local.py", line 336, in __getattr__ 
    return getattr(self._get_current_object(), name) 
    File "/usr/lib/python2.7/site-packages/werkzeug/local.py", line 295, in _get_current_object 
    return self.__local() 
    File "/usr/lib/python2.7/site-packages/flask/globals.py", line 26, in _find_app 
    raise RuntimeError('working outside of application context') 
RuntimeError: working outside of application context 

Questa è la mia funzione di posta elettronica:

@celery.task 
def send_forgot_email(email, ref): 
    global mail 
    msg = Message("Recover your Crusade Gaming Account") 
    msg.recipients = [email] 
    msg.sender = "Crusade Gaming [email protected]" 
    msg.html = \ 
     """ 
     Hello Person,<br/> 

     You have requested your password be reset. <a href="{0}" >Click here recover your account</a> or copy and paste this link in to your browser: {0} <br /> 

     If you did not request that your password be reset, please ignore this. 
     """.format(url_for('account.forgot', ref=ref, _external=True)) 
    mail.send(msg) 

Questo è il mio file di sedano:

from __future__ import absolute_import 

from celery import Celery 

celery = Celery('src.tasks', 
       broker='amqp://', 
       include=['src.util.mail']) 


if __name__ == "__main__": 
    celery.start() 
+0

posta è la flask_mail esempio. la posta viene avviata da un file diverso all'avvio dell'app. – Spuds

+0

Non so quale soluzione sarebbe meglio, aggiungendo il contesto all'intera istanza dell'applicazione di celery o solo alla funzione di callback. Ma si può leggere tutto sul contesto delle applicazioni Flask su http://flask.pocoo.org/docs/appcontext/ –

risposta

3

Flask-mail ha bisogno del contesto applicativo Flask a lavorare correttamente. Un'istanza dell'oggetto applicazione sul lato sedano e utilizzare app.app_context come questo:

with app.app_context(): 
    celery.start() 
+0

Come posso dare accesso a sedici all'app del pallone? Li ho in file separati in questo momento, è sbagliato? – Spuds

+0

Importare l'app nel file di sedano come si farebbe quando si esegue Flask. Potrebbe essere necessario pubblicare il tuo __init __. Py' per l'app Flask o includere più dettagli della configurazione per farmi essere più specifici. –

+0

Avere lo stesso problema, ma istanziare l'app e avviare il sedano all'interno del contesto come quello non funziona. forse perché l'istanza dell'attività è stata creata al di fuori del contesto? –

2

Nel file mail.py, importare la "app" e gli oggetti "Mail". Quindi, usa il contesto della richiesta. Fare qualcosa di simile:

from whateverpackagename import app 
from whateverpackagename import mail 

@celery.task 
def send_forgot_email(email, ref): 
    with app.test_request_context(): 
     msg = Message("Recover your Crusade Gaming Account") 
     msg.recipients = [email] 
     msg.sender = "Crusade Gaming [email protected]" 
     msg.html = \ 
     """ 
     Hello Person,<br/> 
     You have requested your password be reset. <a href="{0}" >Click here recover your account</a> or copy and paste this link in to your browser: {0} <br /> 
     If you did not request that your password be reset, please ignore this. 
     """.format(url_for('account.forgot', ref=ref, _external=True)) 

     mail.send(msg) 
+1

Penso che l'utilizzo di test_request_context in un ambiente non di test non sia una buona idea. – jaapz

+0

Questo ha risolto un problema quando si utilizzava Flask-Babel in combinazione con il sedano. Flask-Babel non caricherà alcuna traduzione senza una richiesta (perché memorizza nella cache le traduzioni sul contesto della richiesta).Oltre a questo, Flask-Babel è in grado di funzionare senza la richiesta. Quindi usare 'test_request_context()' è solo un modo semplice per costruire un contesto funzionale, anche se potrebbe essere un po 'dispendioso. –

2

Non ho alcun punto, così non ho potuto upvote @ codegeek di cui sopra risposta, così ho deciso di scrivere il mio da quando la mia ricerca di un problema come questo è stato aiutato da questo domanda/risposta: ho appena avuto un certo successo nel tentativo di affrontare un problema simile in uno scenario python/pallone/sedano. Anche se il tuo errore è stato quello di provare a usare mentre cercavo di usare url_for in un task di sedani, sospetto che i due fossero legati allo stesso problema e che avresti avuto degli errori derivanti dall'uso di url_for se avessi ho provato ad usarlo prima dello mail.

In assenza di contesto dell'app presente in un'attività di sedici (anche dopo aver incluso uno import app from my_app_module) ricevevo anche degli errori. Avrai bisogno di eseguire l'operazione mail nel contesto del app:

from module_containing_my_app_and_mail import app, mail # Flask app, Flask mail 
from flask.ext.mail import Message # Message class 

@celery.task 
def send_forgot_email(email, ref): 
    with app.app_context(): # This is the important bit! 
     msg = Message("Recover your Crusade Gaming Account") 
     msg.recipients = [email] 
     msg.sender = "Crusade Gaming [email protected]" 
     msg.html = \ 
     """ 
     Hello Person,<br/> 
     You have requested your password be reset. <a href="{0}" >Click here recover your account</a> or copy and paste this link in to your browser: {0} <br /> 
     If you did not request that your password be reset, please ignore this. 
     """.format(url_for('account.forgot', ref=ref, _external=True)) 

     mail.send(msg) 

Se qualcuno è interessato, la mia soluzione per il problema di utilizzare url_for in compiti di sedano può essere trovato here