2013-04-25 22 views
11

Buduję witrynę za pomocą Pythona Flask. Wszystko idzie dobrze, a teraz próbuję wprowadzić seler.Python Flask z selerem z kontekstu aplikacji

To dobrze się układało, dopóki nie spróbowałem wysłać e-maila za pomocą skrzynki pocztowej od selera. Teraz otrzymuję błąd "działający poza kontekstem aplikacji".

pełny traceback jest

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 

To jest moja funkcja mail:

@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) 

To jest mój plik seler:

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

elektronicznej jest flask_mail instancja. Poczta zostanie zainicjowana z innego pliku, gdy aplikacja zostanie uruchomiona. – Spuds

+0

Nie wiem, które rozwiązanie byłoby lepsze, dodając kontekst do całej instancji aplikacji selera lub po prostu funkcję zwrotną. Ale możesz przeczytać wszystko o kontekście aplikacji Flask pod adresem http://flask.pocoo.org/docs/appcontext/ –

Odpowiedz

3

Kolba-mail potrzebuje kontekstu aplikacji kolbę do pracy prawidłowo. Instancję obiektu aplikacji po stronie selera i używać app.app_context tak:

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

Jak zapewnić selerowi dostęp do aplikacji kolby? Mam je teraz w osobnych plikach, czy to źle? – Spuds

+0

Zaimportuj aplikację do pliku selera, tak jak robisz to podczas pracy z kolbą. Być może będziesz musiał opublikować swoje '__init __. Py' dla swojej aplikacji Flask lub zawęzić bardziej szczegółowe informacje o swojej konfiguracji. –

+0

Mając ten sam problem, ale tworzenie aplikacji i uruchamianie selera w takim kontekście nie działa. może dlatego, że instancja zadania została utworzona poza kontekstem? –

2

w pliku mail.py, importować „aplikacji” oraz obiektów „Poczta”. Następnie użyj kontekstu żądania. Zrobić coś takiego:

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

Myślę, że używanie test_request_context w środowisku bez testu nie jest dobrym pomysłem. – jaapz

+0

Rozwiązało to problem podczas używania Flask-Babel w połączeniu z selerem. Flask-Babel nie ładuje żadnych tłumaczeń bez żądania (ponieważ buforuje tłumaczenia w kontekście żądania).Poza tym Flask-Babel może bez problemu działać poprawnie. Używanie 'test_request_context()' jest po prostu prostym sposobem na skonstruowanie funkcjonalnego kontekstu, chociaż może to być trochę marnotrawstwem. –

2

nie mam żadnych punktów, więc nie mogłem upvote @ codegeek tych powyższych odpowiedzi, więc postanowiłem napisać własną rękę, ponieważ moje poszukiwania problemu jak ten był wspomagany przez to pytanie/odpowiedź: Właśnie udało mi się poradzić sobie z podobnym problemem w scenariuszu python/flask/seler. Mimo że Twój błąd polegał na próbie użycia mail, podczas gdy mój błąd polegał na próbie użycia url_for w zadaniu selera, podejrzewam, że oba były powiązane z tym samym problemem i że pojawiłyby się błędy wynikające z użycia url_for, gdybyś miał próbował użyć tego przed mail.

Bez kontekstu aplikacji obecnej w zadaniu selera (nawet po włączeniu import app from my_app_module) również otrzymywałem błędy. Musisz wykonać operację mail w kontekście aplikacji:

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) 

Jeśli ktoś jest zainteresowany, moje rozwiązanie problemu za pomocą url_for w zadaniach selera można znaleźć here

Powiązane problemy