2

I am currently working with a flask application and am trying to send out emails once the user has registered with the site. I am having difficulties with circular imports between the main.py where the app is instantiated and the data_inserts.py where the data is committed to the db and a password is emailed back to the user. For the email functionality, I use Flask-mail extension. The error I get is given below:

ImportError: Cannot import name from 'DataInserts' from relevant_folder.data_inserts

Given below are the details:

main.py:

from relevant_folder.data_inserts import DataInserts
from flask import Flask
from flask_mail import Mail
from conf.mail_settings.py import mail_settings

app = Flask(__name__)
app.config.update[mail_settings]
mail = Mail(app)

@app.route("/register")
def register():
    params = request.json
    DataInserts.add_user(params)

relevant_folder.data_inserts.py:

from main import app
from main.app import mail
from flask_mail import message 

class DataInserts():
    def add_user(self, new_user_json):
        ''' add user name and email to db logic goes here'''
        msg = Message(subject="Subject",
                  sender=app.config.get("MAIL_USERNAME"),
                  recipients=[new_user_json["email"]],
                  body="Hello " + new_user_json["name"] + ", your password is password")
        mail.send(msg)

I feel I have not structured my application properly. Any help greatly appreciated

lordlabakdas
  • 1,163
  • 5
  • 18
  • 33

1 Answers1

2

It should be enough to move the DataInserts import...

from flask import Flask
from flask_mail import Mail
from conf.mail_settings.py import mail_settings

app = Flask(__name__)
app.config.update[mail_settings]
mail = Mail(app)

from relevant_folder.data_inserts import DataInserts

@app.route("/register")
def register():
    params = request.json
    DataInserts.add_user(params)

Alternatively you could pass app and mail instances to the DataInsert class, instead of importing the globals...

Update: Another approach would be using "flask.current_app".

from relevant_folder.data_inserts import DataInserts
from flask import Flask
from flask_mail import Mail
from conf.mail_settings.py import mail_settings

app = Flask(__name__)
app.config.update[mail_settings]
mail = Mail(app)
app.mail = mail

@app.route("/register")
def register():
    params = request.json
    DataInserts.add_user(params)

Notice that I stored the mail instance in app.mail for easy access later.

relevant_folder.data_inserts.py:

from flask import current_app
from flask_mail import message 

class DataInserts():
    def add_user(self, new_user_json):
        ''' add user name and email to db logic goes here'''
        msg = Message(subject="Subject",
                  sender=current_app.config.get("MAIL_USERNAME"),
                  recipients=[new_user_json["email"]],
                  body="Hello " + new_user_json["name"] + ", your password is password")
        current_app.mail.send(msg)

But keep in mind that current_app needs an active application context. when working on a request, the context should alway be there, otherwise you can manually create the context e.g. using with app.app_context():

For more on that topic, see the flask documentation: http://flask.pocoo.org/docs/1.0/appcontext/

Sebastian Loehner
  • 1,302
  • 7
  • 5
  • I still get the same error. I probably should have mentioned this but I also have a couple of other blueprints registered to the app and which uses DataInserts – lordlabakdas Nov 02 '18 at 20:04
  • Well, think about it: in main, before you intantiate app, you import DataInserts - in DataInserts you import app from main, which at this time does not exist yet... – Sebastian Loehner Nov 02 '18 at 20:15
  • True @Sebastian I understand the cause of the issue, but not sure how to solve it – lordlabakdas Nov 02 '18 at 20:17
  • thanks @Sebastian......using `current_app`, I was able to write the user data to the db successfully. But I get the below error when it tries to send mail: `AttributeError: 'Flask' object has no attribute 'mail'` – lordlabakdas Nov 02 '18 at 20:43
  • There does not seem to be a `current_app.mail` object – lordlabakdas Nov 02 '18 at 20:44
  • sorry my mistake, didnt see the edits on the main.py......It is working now....thanks a lot – lordlabakdas Nov 02 '18 at 20:46