Flask cannot import DB

Hello,

I’m getting the following error when running my finalized code in the project Flask Travel Sites.

flask.cli.NoAppException: While importing "app", an ImportError was raised:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/flask/cli.py", line 240, in locate_app
    __import__(module_name)
  File "/home/ccuser/workspace/flask-accounts-authentication/app.py", line 6, in <module>
    import routes, models
  File "/home/ccuser/workspace/flask-accounts-authentication/routes.py", line 3, in <module>
    from forms import RegistrationForm,LoginForm, DestinationForm
  File "/home/ccuser/workspace/flask-accounts-authentication/forms.py", line 4, in <module>
    from models import User
  File "/home/ccuser/workspace/flask-accounts-authentication/models.py", line 3, in <module>
    from app import db, login
ImportError: cannot import name 'db'

My code app.py below:

from flask import Flask

from flask_sqlalchemy import SQLAlchemy

from flask_login import LoginManager, current_user, login_user, logout_user, login_required

app = Flask(__name__)

import routes, models

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///my_database.db'

db = SQLAlchemy(app)

login = LoginManager(app)

login.login_view = 'login'

@login.user_loader

def load_user(id):

    return User.query.get(int(id))

**My code Models.py below **

from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from app import db, login
from flask_login import UserMixin, current_user, login_user, logout_user, login_required



class User(Usermixin, db.Model):
  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(64), index=True, unique=True)
  email = db.Column(db.String(120), index=True, unique=True)
  password_hash = db.Column(db.String(128))
  posts = db.relationship('Post', backref='author', lazy='dynamic')
  
  def __repr__(self):
        return '<User {}>'.format(self.username)

  def set_password(self, password):
    self.password_hash = generate_password_hash(password)

  def check_password(self, password):
    return
check_password_hash(self.password_hash, password)

class Post():
    id = db.Column(db.Integer, primary_key=True)
    city = db.Column(db.String(140))
    country = db.Column(db.String(140))
    description = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post {}>'.format(self.description)

My Code routes.py below

from app import app
from flask import request, render_template, flash, redirect,url_for
from forms import RegistrationForm,LoginForm, DestinationForm
from werkzeug.urls import url_parse
from models import User, Post

  
@app.route('/login', methods=['GET', 'POST'])
def login():
  if current_user.is_authenticated:
    return redirect(url_for('index'))
  form = LoginForm()
  if form.validate_on_submit():
      user = User.query.filter_by(username=form.username.data).first()
      if user is None or not user.check_password(form.password.data):
          flash('Invalid username or password')
          return redirect(url_for('login'))
      login_user(user, remember=form.remember_me.data)
      next_page = request.args.get('next')
      if not next_page or url_parse(next_page).netloc != '':
        next_page = url_for('index')
      return redirect(next_page)
  return render_template('login.html', title='Sign In', form=form)

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('login'))

@app.route('/register', methods=['GET', 'POST'])
def register():
  if current_user.is_authenticated:
    return redirect(url_for('index')) #redirect to appropriate logged in Landing page
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html', title='Register', form=form)

@app.route('/user/<username>',methods=['GET', 'POST'])
@login_required

def user(username):
	user = current_user
	user = User.query.filter_by(username=user.username).first()
	posts = Post.query.filter_by(user_id=user.id)
	if posts is None:
		posts = []
	form = DestinationForm()
	if request.method == 'POST' and form.validate():
		new_destination = Post(city = form.city.data,country=form.country.data,description=form.description.data, user_id=current_user.id)
		db.session.add(new_destination)
		db.session.commit()
	else:
		flash(form.errors)
		unpopular_songs = Song.query.order_by(Song.n).all()[:3]
	destinations = Destination.query.all()
	return render_template('user.html', user=user, posts=posts, form=form)

@app.route('/')
def index():
  #posts = Post.query.all()
  #if not posts:
    #posts=[]
  posts=[]
  return render_template('landing_page.html',posts=posts)


**My code Forms.py below**
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
from models import User


class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    password2 = PasswordField(
        'Repeat Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Register')

class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    remember_me = BooleanField('Remember Me')
    submit = SubmitField('Sign In')

class DestinationForm(FlaskForm):
    city = StringField('city')
    country = StringField('country')
    description = StringField('description')
    submit = SubmitField('Post')

    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user is not None:
            raise ValidationError('Please use a different username.')

    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user is not None:
            raise ValidationError('Please use a different email address.')

I tried looking at this stackoverflow thread but to no avail.

Thanks,

Could someone please help me out?

It looks like you have some circular importing going on.

It’s incredibly useful to map out on paper what your imports and dependencies are.

For example in models.py I see you have

from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from app import db, login

and in app.py you have

from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, current_user, login_user, logout_user, login_required

app = Flask(__name__)

import routes, models

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///my_database.db'
db = SQLAlchemy(app)

The issue here, in app you are importing models before you declare your db. When you import a file, you run the code of that file in the moment, so it’s almost like writing:

from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, current_user, login_user, logout_user, login_required

app = Flask(__name__)

import routes, models

from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from app import db, login

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///my_database.db'
db = SQLAlchemy(app)

… And so you’re basically importing something that doesn’t exist yet! Hence the error.

Hope this helps!

1 Like