2013-04-25 11 views
11

Tôi đang xây dựng một trang web bằng cách sử dụng Flask Flask. Mọi thứ đang diễn ra tốt đẹp và bây giờ tôi đang cố gắng thực hiện cần tây.Bình Flask với cần tây trong bối cảnh ứng dụng

Điều đó cũng tốt cho đến khi tôi cố gửi email bằng bình cầu từ cần tây. Bây giờ tôi nhận được một lỗi "làm việc bên ngoài bối cảnh ứng dụng".

đầy đủ traceback là

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 

Đây là chức năng mail của tôi:

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

Đây là tập tin cần tây của tôi:

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

mail là flask_mail ví dụ. thư được bắt đầu từ một tệp khác khi ứng dụng được bắt đầu. – Spuds

+0

Tôi không biết giải pháp nào sẽ tốt hơn, thêm ngữ cảnh vào toàn bộ ứng dụng cần tây hoặc chỉ gọi hàm gọi lại. Nhưng bạn có thể đọc tất cả về ngữ cảnh ứng dụng Flask tại http://flask.pocoo.org/docs/appcontext/ –

Trả lời

3

Flask-mail cần bối cảnh ứng dụng Flask làm việc đúng. Nhanh chóng các đối tượng ứng dụng ở phía bên cần tây và sử dụng app.app_context như thế này:

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

Làm cách nào để tôi có thể sử dụng cần tây vào ứng dụng bình? Tôi có chúng trong các tập tin riêng biệt ngay bây giờ, là sai? – Spuds

+0

Nhập ứng dụng vào tệp cần tây giống như bạn sẽ làm khi chạy Flask. Bạn có thể phải đăng '__init __. Py' cho ứng dụng Flask của bạn hoặc bao gồm thêm chi tiết về thiết lập của bạn để tôi cụ thể hơn. –

+0

Có cùng một vấn đề, nhưng khởi tạo ứng dụng và bắt đầu cần tây bên trong ngữ cảnh như vậy không hoạt động. có lẽ vì cá thể tác vụ được tạo ra bên ngoài ngữ cảnh? –

2

Trong file mail.py của bạn, nhập "ứng dụng" và "thư" đối tượng. Sau đó, sử dụng ngữ cảnh yêu cầu. Làm một cái gì đó như thế này:

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

Tôi nghĩ rằng việc sử dụng test_request_context trong môi trường không kiểm tra không phải là một ý tưởng hay. – jaapz

+0

Điều này giải quyết được vấn đề khi sử dụng Flask-Babel kết hợp với cần tây. Flask-Babel sẽ không tải bất kỳ bản dịch nào mà không có yêu cầu (vì nó lưu trữ các bản dịch trên ngữ cảnh yêu cầu).Ngoài ra, Flask-Babel có thể hoạt động tốt mà không cần yêu cầu. Vì vậy, việc sử dụng 'test_request_context()' chỉ là một cách đơn giản để xây dựng một ngữ cảnh chức năng, mặc dù nó có thể là một chút lãng phí. –

2

tôi không có bất kỳ điểm, vì vậy tôi không thể upvote @ của codegeek trên câu trả lời, vì vậy tôi quyết định viết riêng của tôi kể từ tìm kiếm của tôi cho một vấn đề như thế này được sự giúp đỡ của thành viên này câu hỏi/trả lời: Tôi vừa có một số thành công cố gắng giải quyết một vấn đề tương tự trong một kịch bản python/bình/cần tây. Mặc dù lỗi của bạn là từ cố gắng sử dụng mail trong khi lỗi của tôi xung quanh cố gắng sử dụng url_for trong một nhiệm vụ cần tây, tôi nghi ngờ cả hai có liên quan đến cùng một vấn đề và rằng bạn sẽ gặp lỗi khi sử dụng url_for nếu bạn có đã cố gắng sử dụng nó trước mail.

Không có ngữ cảnh của ứng dụng có trong tác vụ cần tây (thậm chí sau khi bao gồm import app from my_app_module) Tôi cũng gặp lỗi. Bạn sẽ cần phải thực hiện các hoạt động mail trong bối cảnh của ứng dụng:

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) 

Nếu có ai quan tâm, giải pháp của tôi cho vấn đề của việc sử dụng url_for trong nhiệm vụ cần tây có thể được tìm thấy here