2013-04-25 46 views
11

我正在使用Python Flask構建一個網站。一切都很順利,現在我正在嘗試實施芹菜。Python瓶與芹菜出應用程序的上下文

這樣做還不錯,直到我嘗試使用芹菜瓶信件發送電子郵件。現在我得到了「在應用程序上下文之外工作」的錯誤。

完全回溯是

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 

這是我的郵件功能:

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

這是我的芹菜文件:

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

郵件是flask_mail實例。當應用程序啓動時,電子郵件會從不同的文件啓動。 – Spuds 2013-04-25 17:51:07

+0

我不知道哪個解決方案會更好,將上下文添加到整個芹菜應用程序實例或只是回調函數。 但是你可以在http://flask.pocoo.org/docs/appcontext/ – 2013-04-26 19:42:09

回答

3

瓶郵件需要瓶應用程序上下文工作正確。實例化應用對象的芹菜側並使用app.app_context這樣的:

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

上閱讀有關Flask應用程序上下文的所有信息。如何將芹菜訪問權限授予flask應用程序?我現在把它們放在不同的文件中,這是錯的嗎? – Spuds 2013-04-25 18:43:50

+0

像運行Flask時那樣將應用程序導入芹菜文件。您可能必須將您的'__init __。py'發佈到您的Flask應用程序,或者包含您的設置的更多細節以使我更加具體。 – 2013-04-25 20:47:13

+0

遇到同樣的問題,但實例化應用程序並在上下文中啓動芹菜不起作用。也許是因爲任務實例是在上下文之外創建的? – 2013-06-10 22:14:16

2

在你mail.py文件,導入您的「應用程序」和「郵件」的對象。然後,使用請求上下文。做這樣的事情:

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

我認爲在非測試環境中使用test_request_context並不是一個好主意。 – jaapz 2014-08-13 15:11:31

+0

這個解決了使用Flask-Babel和芹菜組合的問題。 Flask-Babel不會在沒有請求的情況下加載任何翻譯(因爲它在請求上下文中緩存翻譯)。除此之外,Flask-Babel能夠在沒有請求的情況下正常工作。因此,使用'test_request_context()'只是構建功能性上下文的簡單方法,即使它可能有點浪費。 – 2016-01-30 00:37:38

2

我沒有任何積分,所以我不能給予好評@ codegeek的上面的回答,所以我決定,因爲我尋找這樣的一個問題是由這有助於寫我自己問題/答案:我剛剛嘗試在python/flask/celery場景中解決類似的問題。儘管你的錯誤來自於嘗試使用mail,而我的錯誤是在嘗試在芹菜任務中使用url_for,但我懷疑這兩者與相同的問題有關,並且如果你使用了url_for試圖在mail之前使用它。

在芹菜任務中不存在應用程序的上下文(即使在包含import app from my_app_module後)我也出現錯誤。你需要在應用程序的情況下進行操作mail

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) 

如果有人有興趣,我對芹菜任務使用url_for的問題的解決方案,可以發現here