10

I'm new to python and flask and currently working on the Flask Mega-Tutorial, however: I'm stuck getting flask shell to recognize my custom symbols/commands.

When I try to access the model User as a symbol by typing flask shell in my virtual environment, I get NameError: name 'User' is not defined.

User should return: <class 'application.models.User'>, but shows the error instead.

What I don't understand is that the app symbol seems to work fine and returns <Flask 'application'> as it should.

What am I doing wrong here? Something with the imports?

I did some research: this looks like my problem but does not use the app.sell_context_processor decorator.

I tried also variations of my code: both changing import names from app to application as I changed these from the default in the tutorial and using user instead of User (lower vs. uppercase), but nothing seems to work.

Please help me fix this!

Error

    (venv) MBP:books mbpp$ flask shell
    Python 3.6.5 (default, Mar 30 2018, 06:42:10) 
    [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
    App: application
    Instance: /Users/mbpp/Sites/books/instance
    >>> app
    <Flask 'application'>
    >>> User
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    NameError: name 'User' is not defined

My code from application.py

   from application import app, db
   from application.models import User, Book, State, Course, BookTitle, Author

   @app.shell_context_processor
   def make_shell_context():
       return {'db': db, 'User': User, 'State': State, 'BookTitle': BookTitle, 'Author': Author}

and from __init__.py

    from flask import Flask
    from config import Config
    from flask_sqlalchemy import SQLAlchemy
    from flask_migrate import Migrate
    from flask_login import LoginManager

    # initiate the Flask app
    app = Flask(__name__)

    # use the config.py file for configuration
    app.config.from_object(Config)

    # use SQLAlchemy for database management
    db = SQLAlchemy(app)

    # use Flask-Migrate extension for database migration management
    migrate = Migrate(app, db)

    # use Flask-Login extension for login form
    login = LoginManager(app)
    login.login_view = 'login'

    from application import routes, models

and from models.py (I'm building a website where users can sell books)

   from application import db, login
   from datetime import datetime
   from werkzeug.security import generate_password_hash, 
   check_password_hash
   from flask_login import UserMixin

   # create a table to store users
   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))
        phone = db.Column(db.String(64))
        books = db.relationship('Book', backref='seller_name', lazy='dynamic')

    def __repr__(self):
        return '<User: {}>'.format(self.username)

    # create a password hash
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    # check the password hash against a user given password
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    # create a table to store information on a book for sale
        class Book(db.Model):
            id = db.Column(db.Integer, primary_key = True)
            course_id = db.Column(db.Integer, db.ForeignKey('course.id'))
            title = db.Column(db.Integer, db.ForeignKey('booktitle.id'))
            author = db.Column(db.Integer, db.ForeignKey('author.id'))
            price = db.Column(db.Integer)
            isbn = db.Column(db.String(64), index = True)
            state_id = db.Column(db.Integer, db.ForeignKey('state.id'))
            state_description = db.Column(db.String(256))
            seller_id = db.Column(db.Integer, db.ForeignKey('user.id'))
            creation_timestamp = db.Column(db.DateTime, index = True, default = datetime.utcnow)

        def __repr__(self):
            return '<Book: {}>'.format(self.title)

    # create a table to store different states books can be in
        class State(db.Model):
            id = db.Column(db.Integer, primary_key = True)
            name = db.Column(db.String(128), index = True)
            books = db.relationship('Book', backref='state', lazy='dynamic')

        def __repr__(self):
            return '<State: {}>'.format(self.name)

    # create a table to store courses
        class Course(db.Model):
            id = db.Column(db.Integer, primary_key = True)
            name = db.Column(db.String(128), index = True)
            year = db.Column(db.Integer, index = True)
            books = db.relationship('Book', backref='course', lazy='dynamic')

        def __repr__(self):
        return '<Course: {}>'.format(self.name)

    # create a table to store booktitles
        class BookTitle(db.Model):
            id = db.Column(db.Integer, primary_key = True)
            title = db.Column(db.String(128), index = True)
            books = db.relationship('Book', backref='book_title', lazy='dynamic')

        def __repr__(self):
           return '<Book title: {}>'.format(self.title)

    # create a table to store authors
        class Author(db.Model):
        id = db.Column(db.Integer, primary_key = True)
        name = db.Column(db.String(128), index = True)
        books = db.relationship('Book', backref='author_name', lazy='dynamic')

        def __repr__(self):
            return '<Author: {}>'.format(self.name)

     # user loader for Flask-Login extension, gets users ID
     @login.user_loader
     def load_user(id):
         return User.query.get(int(id))
James Parsons
  • 6,097
  • 12
  • 68
  • 108
StackTT
  • 241
  • 1
  • 2
  • 9
  • 1
    You consistently misspelled `user` with a lowercase `U`. – tripleee Apr 03 '18 at 09:23
  • @tripleee Just tried to use `User` in the `flask shell`, but that gives the same error. :/ Or is that not what you mean by *consistently*? – StackTT Apr 03 '18 at 09:37
  • That's what I mean. Maybe [edit] the question to clarify this. I'm unfamiliar with this part of Flask but expecting a misspelled name to work is obviously unrealistic. – tripleee Apr 03 '18 at 09:49
  • @tripleee Thanks, edited the Q to clarify that I tried both `User` and `user`. – StackTT Apr 03 '18 at 09:55
  • 2
    @StackTT what is the value of your `FLASK_APP` environment variable? – Miguel Grinberg Apr 03 '18 at 17:31
  • 1
    @Miguel `export FLASK_APP=application.py` – StackTT Apr 04 '18 at 16:44
  • so you have a `application.py` and a `application` package in the same directory level? Can you disambiguate that to make sure that isn't the source of the problem? – Miguel Grinberg Apr 05 '18 at 00:28
  • @Miguel Yes, I have an application.py and a /application/ folder with /templates/ (for html tamplets) and __init__.py, routes.py, models.py and others in it. Should I change that folder name or application.py file name? – StackTT Apr 05 '18 at 12:37
  • Doesn't matter which, pick one and change it. You can't have a module and a package of the same name, there is no way to be specific about which one of the two you are importing from. – Miguel Grinberg Apr 05 '18 at 17:10
  • @Miguel Thanks a lot Miguel, that works indeed. Changed my application.py into theapp.py and now `flask shell` works like a charm! I also did not need to change anything in my files, apart from running `export FLASK_APP=theapp.py`. – StackTT Apr 12 '18 at 16:07
  • @Miguel If you want to submit your answer I'm ready to accept it as the answer! – StackTT Apr 12 '18 at 16:16

2 Answers2

14

Thanks a lot to Miguel, the writer of the FLASK Mega Tutorial (go check that out) wo solved my problem!

As he pointed out in a comment below my question: you cannot have a module and a package with the same name. So no application folder and application.py at the same time.

Solution:

I changed my 'application.py into 'theapp.py' and now flask shell works like a charm! I did not need to change anything in my files, apart from running export FLASK_APP=theapp.py in the terminal.

Community
  • 1
  • 1
StackTT
  • 241
  • 1
  • 2
  • 9
  • 1
    This one have worked for me as well. It should be included as a warning on the tutorial, though. – Dennis Braga May 12 '19 at 20:31
  • Does not work for me. I had also used `microblog` for both the script and the dir. Changed the script to app.py and fixed the references. flask shell does not register it and the environment is set. I checked with `from envs import env` then `env("FLASK_APP")` which prints `'app.py'`. It did also not work by setting `export FLASK_APP=app.py` as an alternative method. – CoderGuy123 Aug 18 '19 at 02:11
  • 1
    Found the issue. By comparing with the premade code, I found that my `app.py` file should be in the main dir, not inside the `app` dir. – CoderGuy123 Aug 18 '19 at 03:26
  • Further info on the background: https://stackoverflow.com/questions/6393861/how-python-deals-with-module-and-package-having-the-same-name – Joe Aug 01 '20 at 06:09
  • depending on your application set up, you can use a "manage.py" script for managing some setup including the shell context you need a @app.shell_context_processor decorator and make_shell_context() function which returns a "context" dictionnary mapping from "Model" Object to "Context" Object (making them visible in the shell context) – user3680029 Oct 19 '21 at 13:24
12

Flask needs to be told how to import it, by setting the

FLASK_APP:(venv) $ export FLASK_APP=microblog.py

If you are using Microsoft Windows, use set instead of export in the command above.

Linus Unnebäck
  • 23,234
  • 15
  • 74
  • 89
Magomed Shamaev
  • 198
  • 2
  • 5