The Flask Mega-Tutorial Part XVIII: Deployment on Heroku

This is the eighteenth installment of the Flask Mega-Tutorial series, in which I'm going to deploy Microblog to the Heroku cloud platform.

For your reference, below is a list of the articles in this series.

Note 1: If you are looking for the legacy version of this tutorial, it's here.

Note 2: If you would like to support my work on this blog, or just don't have patience to wait for weekly articles, I am offering the complete version of this tutorial packaged as an ebook or a set of videos. For more information, visit courses.miguelgrinberg.com.

In the previous article I showed you the "traditional" way to host a Python application, and I gave you two actual examples of deployment to Linux based servers. If you are not used to manage a Linux system, you probably thought that the amount of effort that needs to be put into the task was big, and that surely there must be an easier way.

In this chapter I'm going to show you a completely different approach, in which you rely on a third-party cloud hosting provider to perform most of the administration tasks, freeing you to spend more time working on your application.

Many cloud hosting providers offer a managed platform on which applications can run. All you need to provide to have your application deployed on these platforms is the actual application, because the hardware, operating system, scripting language interpreters, database, etc. are all managed by the service. This type of service is called Platform as a Service, or PaaS.

Sounds too good to be true, right?

I will look at deploying Microblog to Heroku, a popular cloud hosting service that is also very friendly for Python applications. I picked Heroku not only because it is popular, but also because it has a free service level that will allow you to follow me and do a complete deployment without spending any money.

The GitHub links for this chapter are: Browse, Zip, Diff.

Hosting on Heroku

Heroku was one of the first platform as a service providers. It started as a hosting option for Ruby based applications, but then grew to support many other languages like Java, Node.js and of course Python.

Deploying a web application to Heroku is done through the git version control tool, so you must have your application in a git repository. Heroku looks for a file called Procfile in the application's root directory for instructions on how to start the application. For Python projects, Heroku also expects a requirements.txt file that lists all the module dependencies that need to be installed. After the application is uploaded to Heroku's servers through git, you are essentially done and just need to wait a few seconds until the application is online. It's really that simple.

The different service tiers Heroku offers allow you to choose how much computing power and time you get for your application, so as your user base grows you will need to buy more units of computing, which Heroku calls "dynos".

Ready to try Heroku? Let's get started!

Creating Heroku account

Before you can deploy to Heroku you need to have an account with them. So visit heroku.com and create a free account. Once you have an account and log in to Heroku, you will have access to a dashboard, where all your applications are listed.

Installing the Heroku CLI

Heroku provides a command-line tool for interacting with their service called Heroku CLI, available for Windows, Mac OS X and Linux. The documentation includes installation instructions for all the supported platforms. Go ahead and install it on your system if you plan on deploying the application to test the service.

The first thing you should do once the CLI is installed is login to your Heroku account:

$ heroku login

Heroku CLI will ask you to enter your email address and your account password. Your authenticated status will be remembered in subsequent commands.

Setting Up Git

The git tool is core to the deployment of applications to Heroku, so you must install it on your system if you don't have it yet. If you don't have a package available for your operating system, you can visit the git site to download an installer.

There are a lot of reasons why using git for your projects makes sense. If you plan to deploy to Heroku, you have one more, because to deploy to Heroku, your application must be in a git repository. If you are going to do a test deployment for Microblog, you can clone the application from GitHub:

$ git clone https://github.com/miguelgrinberg/microblog
$ cd microblog
$ git checkout v0.18

The git checkout command selects the specific commit that has the application at the point in its history that corresponds to this chapter.

If you prefer to work with your own code instead of mine, you can transform your own project into a git repository by running git init . on the top-level directory (note the period after init, which tells git that you want to create the repository in the current directory).

Creating a Heroku Application

To register a new application with Heroku, you use the apps:create command from the root directory of the application, passing the application name as the only argument:

$ heroku apps:create flask-microblog
Creating flask-microblog... done
http://flask-microblog.herokuapp.com/ | https://git.heroku.com/flask-microblog.git

Heroku requires that applications have a unique name. The name flask-microblog that I used above is not going to be available to you because I'm using it, so you will need to pick a different name for your deployment.

The output of this command will include the URL that Heroku assigned to the application, and also its git repository. Your local git repository will be configured with an extra remote, called heroku. You can verify that it exists with the git remote command:

$ git remote -v
heroku  https://git.heroku.com/flask-microblog.git (fetch)
heroku  https://git.heroku.com/flask-microblog.git (push)

Depending on how you created your git repository, the output of the above command could also include another remote called origin.

The Ephemeral File System

The Heroku platform is different to other deployment platforms in that it features an ephemeral file system that runs on a virtualized platform. What does that mean? It means that at any time, Heroku can reset the virtual server on which your server runs back to a clean state. You cannot assume that any data that you save to the file system will persist, and in fact, Heroku recycles servers very often.

Working under these conditions introduces some problems for my application, which uses a few files:

  • The default SQLite database engine writes data in a disk file
  • Logs for the application are also written to the file system
  • The compiled language translation repositories are also written to local files

The following sections will address these three areas.

Working with a Heroku Postgres Database

To address the first problem, I'm going to switch to a different database engine. In Chapter 17 you saw me use a MySQL database to add robustness to the Ubuntu deployment. Heroku has a database offering of its own, based on the Postgres database, so I'm going to switch to that to avoid the file-based SQLite.

Databases for Heroku applications are provisioned with the same Heroku CLI. In this case I'm going to create a database on the free tier:

$ heroku addons:add heroku-postgresql:hobby-dev
Creating heroku-postgresql:hobby-dev on flask-microblog... free
Database has been created and is available
 ! This database is empty. If upgrading, you can transfer
 ! data from another database with pg:copy
Created postgresql-parallel-56076 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

The URL for the newly created database is stored in a DATABASE_URL environment variable that will be available when the application runs. This is very convenient, because the application already looks for the database URL in that variable.

Logging to stdout

Heroku expects applications to log directly to stdout. Anything the application prints to the standard output is saved and returned when you use the heroku logs command. So I'm going to add a configuration variable that indicates if I need to log to stdout or to a file like I've been doing. Here is the change in the configuration:

config.py: Option to log to stdout.

class Config(object):
    # ...
    LOG_TO_STDOUT = os.environ.get('LOG_TO_STDOUT')

Then in the application factory function I can check this configuration to know how to configure the application's logger:

app/__init__.py: Log to stdout or file.

def create_app(config_class=Config):
    # ...
    if not app.debug and not app.testing:
        # ...

        if app.config['LOG_TO_STDOUT']:
            stream_handler = logging.StreamHandler()
            if not os.path.exists('logs'):
            file_handler = RotatingFileHandler('logs/microblog.log',
                                               maxBytes=10240, backupCount=10)
                '%(asctime)s %(levelname)s: %(message)s '
                '[in %(pathname)s:%(lineno)d]'))

        app.logger.info('Microblog startup')

    return app

So now I need to set the LOG_TO_STDOUT environment variable when the application runs in Heroku, but not in other configurations. The Heroku CLI makes this easy, as it provides an option to set environment variables to be used at runtime:

$ heroku config:set LOG_TO_STDOUT=1
Setting LOG_TO_STDOUT and restarting flask-microblog... done, v4

Compiled Translations

The third aspect of Microblog that relies on local files is the compiled language translation files. The more direct option to ensure those files never disappear from the ephemeral file system is to add the compiled language files to the git repository, so that they become part of the initial state of the application once it is deployed to Heroku.

A more elegant option, in my opinion, is to include the flask translate compile command in the start up command given to Heroku, so that any time the server is restarted those files are compiled again. I'm going to go with this option, since I know that my start up procedure is going to require more than one command anyway, since I also need to run the database migrations. So for now, I will set this problem aside, and will revisit it later when I write the Procfile.

Elasticsearch Hosting

Elasticsearch is one of the many services that can be added to a Heroku project, but unlike Postgres, this is not a service provided by Heroku, but by third parties that partner with Heroku to provide add-ons. At the time I'm writing this, there are three different providers of an integrated Elasticsearch service.

Before you configure Elasticsearch, be aware that Heroku requires your account to have a credit card on file before any third party add-on is installed, even if you stay within their free tiers. If you prefer not to provide your credit card to Heroku, then skip this section. You will still be able to deploy the application, but the search functionality is not going to work.

Out of the Elasticsearch options that are available as add-ons, I decided to try SearchBox, which comes with a free starter plan. To add SearchBox to your account, you have to run the following command while being logged in to Heroku:

$ heroku addons:create searchbox:starter

This command will deploy an Elasticsearch service and leave the connection URL for the service in a SEARCHBOX_URL environment variable associated with your application. Once more keep in mind that this command will fail unless you add your credit card to your Heroku account.

If you recall from Chapter 16, my application looks for the Elasticsearch connection URL in the ELASTICSEARCH_URL variable, so I need to add this variable and set it to the connection URL assigned by SearchBox:

$ heroku config:get SEARCHBOX_URL
$ heroku config:set ELASTICSEARCH_URL=<your-elasticsearch-url>

Here I first asked Heroku to print the value of SEARCHBOX_URL, and then I added a new environment variable with the name ELASTICSEARCH_URL set to that same value.

Updates to Requirements

Heroku expects the dependencies to be in the requirements.txt file, exactly like I defined it in Chapter 15. But for the application to run on Heroku I need to add two new dependencies to this file.

Heroku does not provide a web server of its own. Instead, it expects the application to start its own web server on the port number given in the environment variable $PORT. Since the Flask development web server is not robust enough to use for production, I'm going to use gunicorn again, the server recommended by Heroku for Python applications.

The application will also be connecting to a Postgres database, and for that SQLAlchemy requires the psycopg2 package to be installed.

Both gunicorn and psycopg2 need to be added to the requirements.txt file.

The Procfile

Heroku needs to know how to execute the application, and for that it uses a file named Procfile in the root directory of the application. The format of this file is simple, each line includes a process name, a colon, and then the command that starts the process. The most common type of application that runs on Heroku is a web application, and for this type of application the process name should be web. Below you can see a Procfile for Microblog:

Procfile: Heroku Procfile.

web: flask db upgrade; flask translate compile; gunicorn microblog:app

Here I defined the command to start the web application as three commands in sequence. First I run a database migration upgrade, then I compile the language translations, and finally I start the server.

Because the first two sub-commands are based on the flask command, I need to add the FLASK_APP environment variable:

$ heroku config:set FLASK_APP=microblog.py
Setting FLASK_APP and restarting flask-microblog... done, v4
FLASK_APP: microblog.py

The application also relies on other environment varialbes, such as those that configure the email server or the token for the live translations. Those need to be added with addition heroku config:set commands.

The gunicorn command is simpler than what I used for the Ubuntu deployment, because this server has a very good integration with the Heroku environment. For example, the $PORT environment variable is honored by default, and instead of using the -w option to set the number of workers, heroku recommends adding a variable called WEB_CONCURRENCY, which gunicorn uses when -w is not provided, giving you the flexibility to control the number of workers without having to modify the Procfile.

Deploying the Application

All the preparatory steps are complete, so now it is time to run the deployment. To upload the application to Heroku's servers for deployment, the git push command is used. This is similar to how you push changes in your local git repository to GitHub or other remote git server.

And now I have reached the most interesting part, where I push the application to our Heroku hosting account. This is actually pretty simple, I just have to use git to push the application to the master branch of the Heroku git repository. There are a couple of variations on how to do this, depending on how you created your git repository. If you are using my v0.18 code, then you need to create a branch based on this tag, and push it as the remote master branch, as follows:

$ git checkout -b deploy
$ git push heroku deploy:master

If instead, you are working with your own repository, then your code is already in a master branch, so you first need to make sure that your changes are committed:

$ git commit -a -m "heroku deployment changes"

And then you can run the following to start the deployment:

$ git push heroku master

Regardless of how you push the branch, you should see the following output from Heroku:

$ git push heroku deploy:master
Counting objects: 247, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (238/238), done.
Writing objects: 100% (247/247), 53.26 KiB | 3.80 MiB/s, done.
Total 247 (delta 136), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: -----> Python app detected
remote: -----> Installing python-3.6.2
remote: -----> Installing pip
remote: -----> Installing requirements with pip
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: -----> Compressing...
remote:        Done: 57M
remote: -----> Launching...
remote:        Released v5
remote:        https://flask-microblog.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/flask-microblog.git
 * [new branch]      deploy -> master

The label heroku that we used in the git push command is the remote that was automatically added by the Heroku CLI when the application was created. The deploy:master argument means that I'm pushing the code from the local repository referenced by the deploy branch to the master branch on the Heroku repository. When you work with your own projects, you will likely be pushing with the command git push heroku master, which pushes your local master branch. Because of the way this project is structured, I'm pushing a branch that is not master, but the destination branch on the Heroku side always needs to be master as that is the only branch that Heroku accepts for deployment.

And that is it, the application should now be deployed at the URL that you were given in the output of the command that created the application. In my case, the URL was https://flask-microblog.herokuapp.com, so that is what I need to type to access the application.

If you want to see the log entries for the running application, use the heroku logs command. This can be useful if for any reason the application fails to start. If there were any errors, those will be in the logs.

Deploying Application Updates

To deploy a new version of the application, you just need to run a new git push command with the new code. This will repeat the deployment process, take the old deployment offline, and then replace it with the new code. The commands in the Procfile will run again as part of the new deployment, so any new database migrations or translations will be updated during the process.


  • #126 Miguel Grinberg said 2020-06-29T17:29:29Z

    @Vidhi: I can't really help you if you don't provide any details regarding how is your application not working.

  • #127 Edmund said 2020-07-16T16:05:34Z

    Amazing tutorials, I really appreciate the foot up. I got my app running in heroku already with their mysql add-on but I'd like to switch to postgres for the tight integration. I'm confused, as your section shows me how to create the db on heroku (done) but I can't see how you create tables (I was expecting to use a flask db command) or configure the code to use it. I see the environment variable DATABASE_URL provides the link to the db url, but it feels like I'm missing other steps. My code complains that:

    init.py", line 883, in apply_driver_hacks if sa_url.drivername.startswith('mysql'): AttributeError: 'NoneType' object has no attribute 'drivername'

    but I can't see that I've told it to use mysql anywhere. The heroku help pages talk about importing psycopg2 (and you have installed it) and using:

    conn = psycopg2.connect(DATABASE_URL, sslmode='require')

    but I can't see that you've done that in your code anywhere. What am I missing?

  • #128 Miguel Grinberg said 2020-07-18T14:01:52Z

    @Edmund: The command that runs in Heroku incluides a flask db upgrade statement. Your error suggests that the DATABASE_URL variable isn't set, or isn't correctly imported into the Flask config object.

  • #129 Donal said 2020-07-23T10:56:35Z

    Re #93/94 "no such index [post]"/"your problem is that your database has content that was never synced to elasticsearch".

    That was my situation also. I deleted all posts and it worked perfectly from there on.

  • #130 Filipe Bezerra said 2020-07-29T05:36:28Z

    For who is facing this error:

    elasticsearch.exceptions.NotFoundError: NotFoundError(404, 'index_not_found_exception', 'no such index [posts]', posts, index_expression)

    You need to create the index because it looks like the automatic creation of indices is disabled (by setting action.auto_create_index to false the SearchBox configuration).

    ... def add_to_index(index, model): ... current_app.elasticsearch.indices.create(index=index, ignore=400) current_app.elasticsearch.index(index=index, id=model.id, body=payload)

  • #131 yashvini said 2020-09-04T13:20:36Z

    Hey Michael! Awesome blog. Whenver i try to push to heroku, i get this error

    remote: -----> Python app detected remote: -----> Installing python-3.6.12 remote: -----> Installing pip 20.1.1, setuptools 47.1.1 and wheel 0.34.2 remote: -----> Installing SQLite3 remote: -----> Installing requirements with pip remote: Collecting alembic==0.9.6 remote: Downloading alembic-0.9.6.tar.gz (998 kB) remote: Collecting Babel==2.5.1 remote: Downloading Babel-2.5.1-py2.py3-none-any.whl (6.8 MB) remote: Collecting blinker==1.4 remote: Downloading blinker-1.4.tar.gz (111 kB) remote: Collecting certifi==2017.7.27.1 remote: Downloading certifi-2017.7.27.1-py2.py3-none-any.whl (349 kB) remote: Collecting chardet==3.0.4 remote: Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB) remote: Collecting click==6.7 remote: Downloading click-6.7-py2.py3-none-any.whl (71 kB) remote: Collecting dominate==2.3.1 remote: Downloading dominate-2.3.1.tar.gz (27 kB) remote: Collecting elasticsearch==7.5.1 remote: Downloading elasticsearch-7.5.1-py2.py3-none-any.whl (86 kB) remote: Collecting Flask==1.0.2 remote: Downloading Flask-1.0.2-py2.py3-none-any.whl (91 kB) remote: Collecting Flask-Babel==0.11.2 remote: Downloading Flask_Babel-0.11.2-py2.py3-none-any.whl (9.3 kB) remote: Collecting Flask-Bootstrap== remote: Downloading Flask-Bootstrap- (456 kB) remote: Collecting Flask-HTTPAuth==4.0.0 remote: Downloading Flask_HTTPAuth-4.0.0-py2.py3-none-any.whl (5.6 kB) remote: Collecting Flask-Login==0.4.0 remote: Downloading Flask_Login-0.4.0-py2.py3-none-any.whl (15 kB) remote: Collecting Flask-Mail==0.9.1 remote: Downloading Flask-Mail-0.9.1.tar.gz (45 kB) remote: Collecting Flask-Migrate==2.1.1 remote: Downloading Flask_Migrate-2.1.1-py2.py3-none-any.whl (13 kB) remote: Collecting Flask-Moment==0.5.2 remote: Downloading Flask_Moment-0.5.2-py2.py3-none-any.whl (3.7 kB) remote: Collecting Flask-SQLAlchemy==2.3.2 remote: Downloading Flask_SQLAlchemy-2.3.2-py2.py3-none-any.whl (16 kB) remote: Collecting Flask-WTF==0.14.2 remote: Downloading Flask_WTF-0.14.2-py2.py3-none-any.whl (14 kB) remote: Collecting guess_language-spirit==0.5.3 remote: Downloading guess_language-spirit-0.5.3.tar.bz2 (81 kB) remote: Collecting idna==2.6 remote: Downloading idna-2.6-py2.py3-none-any.whl (56 kB) remote: Collecting itsdangerous==0.24 remote: Downloading itsdangerous-0.24.tar.gz (46 kB) remote: Collecting Jinja2==2.10 remote: Downloading Jinja2-2.10-py2.py3-none-any.whl (126 kB) remote: Collecting Mako==1.0.7 remote: Downloading Mako-1.0.7.tar.gz (564 kB) remote: Collecting MarkupSafe==1.0 remote: Downloading MarkupSafe-1.0.tar.gz (14 kB) remote: ERROR: Command errored out with exit status 1: remote: command: /app/.heroku/python/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-n2irzyyp/MarkupSafe/setup.py'"'"'; file='"'"'/tmp/pip-install-n2irzyyp/MarkupSafe/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-f5odi7bw remote: cwd: /tmp/pip-install-n2irzyyp/MarkupSafe/ remote: Complete output (5 lines): remote: Traceback (most recent call last): remote: File "<string>", line 1, in <module> remote: File "/tmp/pip-install-n2irzyyp/MarkupSafe/setup.py", line 6, in <module> remote: from setuptools import setup, Extension, Feature remote: ImportError: cannot import name 'Feature' remote: ---------------------------------------- remote: ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output. remote: ! Push rejected, failed to compile Python app. remote: remote: ! Push failed remote: Verifying deploy... remote: remote: ! Push rejected to flask-microblogf. remote: To https://git.heroku.com/flask-microblogf.git ! [remote rejected] master -> master (pre-receive hook declined)

    Can't find the setup.py, dont know why it cant import feature since I used a clone of your code on github. Please help:) Thanks!!

  • #132 Miguel Grinberg said 2020-09-04T15:00:00Z

    @yashvini: usually when you get a strange error like this the best thing to do is to Google it. Turns out the error is already reported: https://github.com/pallets/markupsafe/issues/57. The solution is to upgrade MarkupSafe to 1.1.1. After you edit your requirements file to use this version the push should work.

  • #133 Tom said 2020-09-06T14:50:47Z

    Hi Miguel,

    thank you once again for the really great mega-tutorial!

    When I deploy the code to heroku - I get

    remote: -----> Python app detected remote: ! Python has released a security update! Please consider upgrading to python-3.6.12 remote: Learn More: https://devcenter.heroku.com/articles/python-runtimes remote: -----> Requirements file has been changed, clearing cached dependencies remote: -----> Installing python-3.6.10

    How could I upgrade the packages/dependencies so that the acceptable python version is, say, 3.7?

    regards, Tom

  • #134 Miguel Grinberg said 2020-09-06T23:01:39Z

    @Tom: this is covered in the Heroku documentation: https://devcenter.heroku.com/articles/python-runtimes.

  • #135 yasmin said 2020-09-30T15:18:38Z

    Hello Miguel I'm having a large project based on your which I've been working on for the last three years (I've learned flask from scratch from you). I have everything figured out and working. Except the Heroku migration which I have trouble with again and again. Could you make a Flask-Heroku migration tutorial, especially how to get rid of hundreds of version files without loosing any dat. Thanx in advance Yasmin

  • #136 Miguel Grinberg said 2020-09-30T15:52:14Z

    @yasmin: Your question relates to Alembic more than anything I have created. To my knowledge there are no automated tools to combine multiple migration files into one, but this is something that you can do manually once you learn the format those migration scripts are linked by Alembic.

  • #137 Gitau Harrison said 2020-10-04T05:37:24Z

    I am facing a database issue after successfully deploying my app on heroku.

    First, heroku addons:add heroku-postgresql:hobby-dev works.

    When I run heroku pg:info DATABASE, I get:

    === DATABASE_URL Plan: Hobby-dev Status: Available Connections: 1/20 PG Version: 12.4 Created: 2020-10-04 04:29 UTC Data Size: 7.9 MB Tables: 0 Rows: 0/10000 (In compliance) Fork/Follow: Unsupported Rollback: Unsupported Continuous Protection: Off Add-on: postgresql-asymmetrical-03894

    Then, heroku run flask db upgrade (Procfile has web: flask db upgrade), this is what I get:

    Traceback (most recent call last): File "/app/.heroku/python/bin/flask", line 8, in &lt;module&gt; sys.exit(main()) File "/app/.heroku/python/lib/python3.6/site-packages/flask/cli.py", line 967, in main cli.main(args=sys.argv[1:], prog_name="python -m flask" if as_module else None) File "/app/.heroku/python/lib/python3.6/site-packages/flask/cli.py", line 586, in main return super(FlaskGroup, self).main(*args, **kwargs) File "/app/.heroku/python/lib/python3.6/site-packages/click/core.py", line 782, in main rv = self.invoke(ctx) File "/app/.heroku/python/lib/python3.6/site-packages/click/core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/app/.heroku/python/lib/python3.6/site-packages/click/core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/app/.heroku/python/lib/python3.6/site-packages/click/core.py", line 1066, in invoke return ctx.invoke(self.callback, **ctx.params) File "/app/.heroku/python/lib/python3.6/site-packages/click/core.py", line 610, in invoke return callback(*args, **kwargs) File "/app/.heroku/python/lib/python3.6/site-packages/click/decorators.py", line 21, in new_func return f(get_current_context(), *args, **kwargs) File "/app/.heroku/python/lib/python3.6/site-packages/flask/cli.py", line 426, in decorator return __ctx.invoke(f, *args, **kwargs) File "/app/.heroku/python/lib/python3.6/site-packages/click/core.py", line 610, in invoke return callback(*args, **kwargs) File "/app/.heroku/python/lib/python3.6/site-packages/flask_migrate/cli.py", line 134, in upgrade _upgrade(directory, revision, sql, tag, x_arg) File "/app/.heroku/python/lib/python3.6/site-packages/flask_migrate/__init__.py", line 96, in wrapped f(*args, **kwargs) File "/app/.heroku/python/lib/python3.6/site-packages/flask_migrate/__init__.py", line 271, in upgrade command.upgrade(config, revision, sql=sql, tag=tag) File "/app/.heroku/python/lib/python3.6/site-packages/alembic/command.py", line 298, in upgrade script.run_env() File "/app/.heroku/python/lib/python3.6/site-packages/alembic/script/base.py", line 489, in run_env util.load_python_file(self.dir, "env.py") File "/app/.heroku/python/lib/python3.6/site-packages/alembic/util/pyfiles.py", line 98, in load_python_file module = load_module_py(module_id, path) File "/app/.heroku/python/lib/python3.6/site-packages/alembic/util/compat.py", line 184, in load_module_py spec.loader.exec_module(module) File "&lt;frozen importlib._bootstrap_external&gt;", line 678, in exec_module File "&lt;frozen importlib._bootstrap&gt;", line 219, in _call_with_frames_removed File "migrations/env.py", line 27, in &lt;module&gt; str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) AttributeError: 'NoneType' object has no attribute 'engine'

    I can see that AttributeError: 'NoneType' object has no attribute 'engine'. Looking it up online, I learnt that my SQLALCHEMY_DATABASE_URI should be set to the actual URL in a '.env' file SQLALCHEMY error

    Now, I went right into chapter 18(here) without completing the Deployment on Linux chapter during which you created a .env file containing needed environment variables.


    Would this be the reason why my heroku database is not updated?

    Every time, I get database error:

    sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "user" does not exist 2020-10-04T05:30:18.432952+00:00 app[web.1]: LINE 2: FROM "user" 2020-10-04T05:30:18.432952+00:00 app[web.1]: ^ 2020-10-04T05:30:18.432953+00:00 app[web.1]: 2020-10-04T05:30:18.432953+00:00 app[web.1]: [SQL: SELECT "user".id AS user_id, "user".username AS user_username, "user".email AS user_email, "user".password_hash AS user_password_hash, "user".about_me AS user_about_me, "user".last_seen AS user_last_seen 2020-10-04T05:30:18.432954+00:00 app[web.1]: FROM "user" 2020-10-04T05:30:18.432954+00:00 app[web.1]: WHERE "user".username = %(username_1)s 2020-10-04T05:30:18.432954+00:00 app[web.1]: LIMIT %(param_1)s] 2020-10-04T05:30:18.432955+00:00 app[web.1]: [parameters: {'username_1': 'harry', 'param_1': 1}] 2020-10-04T05:30:18.432960+00:00 app[web.1]: (Background on this error at: http://sqlalche.me/e/f405)

    My config file is set up like the tutorial's and importation is done similarly.

  • #138 Miguel Grinberg said 2020-10-04T16:13:55Z

    @Gitau: the important question is if your Heroku environment has the DATABASE_URL variable defined or not.

  • #139 Gitau Harrison said 2020-10-05T04:30:22Z

    Heroku environment has the DATABASE_URL variable. When I run:

    $ heroku config:get DATABASE_URL

    I get a postgres URL. I can confirm that this URL is the same one as the one from the postgresql URI in my dashboard. But I still get the error:

    sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "user" does not exist

    I have noted that when I push to heroku, right after the Python app has been detected, I have:

    remote -------&gt; Installing SQLite3

    Comparing that you the output displayed in the tutorial, you don't have that. What could I be missing?

  • #140 Gitau Harrison said 2020-10-05T07:20:07Z

    I have been able to fix the user issue. It lied in the application factory. I missed to add db argument when initializing migrate. All I needed to do was to add db to it.


    def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) login.init_app(app) db.init_app(app) migrate.init_app(app) #&lt;--------------- moment.init_app(app) babel.init_app(app) mail.init_app(app) bootstrap.init_app(app)

    Fixed error:

    def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) login.init_app(app) db.init_app(app) migrate.init_app(app, db) #&lt;--------------- moment.init_app(app) babel.init_app(app) mail.init_app(app) bootstrap.init_app(app)

    Now, when I run python heroku run flask db upgrade, the PostreSQL tables are updated and I can see them.

  • #141 Miguel Grinberg said 2020-10-05T07:51:34Z

    @Gitau: Did you run a database upgrade on your Heroku database? The error means that the user table does not exist. Try running "flask db upgrade" on your Heroku app.

  • #142 Gitau Harrison said 2020-10-06T00:16:41Z

    I am not sure why live translation does not work on the deployed app. Locally, the translate link is displayed, and on click, it enables live language translation. There is no Translate link on the deployed app even though the code is exactly the same as the one locally.

    During set up, I have already configured MS_TRANSLATOR_KEY in Heroku, that is why it is a bit strange that it does not work. What could be the issue?

  • #143 Miguel Grinberg said 2020-10-06T09:16:09Z

    @Gitau: if the translate button does not appear that means the language detection isn't working so you need to check that part.

  • #144 penrudee said 2020-10-15T10:01:08Z

    Hi me agian

    I deploy web app on HEROKU everything fine but only sending reset password from gmail and HEROKU log show me error : (sending local work) smtplib.SMTPServerDisconnected: please run connect() first

    and i don't know how to config it cause i google and not see solution to solve it.

    please help me

  • #145 Miguel Grinberg said 2020-10-15T16:00:30Z

    @penrudee: your Google credentials are incorrect, or you haven't configured your Google account to have less-secure clients, as shown in the tutorial.

  • #146 Samyak Jain said 2020-12-23T16:37:41Z

    When I run git push heroku master, everything works fine. But when I visit my application url, I see an 'Application Error' message, which tells me to run "heroku logs --tail" to see the details. When I run this command, here is the entire message I get:

    2020-12-23T16:35:00.221164+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker 2020-12-23T16:35:00.221165+00:00 app[web.1]: worker.init_process() 2020-12-23T16:35:00.221165+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 119, in init_process 2020-12-23T16:35:00.221165+00:00 app[web.1]: self.load_wsgi() 2020-12-23T16:35:00.221166+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi 2020-12-23T16:35:00.221166+00:00 app[web.1]: self.wsgi = self.app.wsgi() 2020-12-23T16:35:00.221167+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi 2020-12-23T16:35:00.221167+00:00 app[web.1]: self.callable = self.load() 2020-12-23T16:35:00.221168+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 49, in load 2020-12-23T16:35:00.221168+00:00 app[web.1]: return self.load_wsgiapp() 2020-12-23T16:35:00.221169+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp 2020-12-23T16:35:00.221169+00:00 app[web.1]: return util.import_app(self.app_uri) 2020-12-23T16:35:00.221170+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 358, in import_app 2020-12-23T16:35:00.221170+00:00 app[web.1]: mod = importlib.import_module(module) 2020-12-23T16:35:00.221170+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/init.py", line 126, in import_module 2020-12-23T16:35:00.221171+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level) 2020-12-23T16:35:00.221171+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import 2020-12-23T16:35:00.221172+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load 2020-12-23T16:35:00.221174+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked 2020-12-23T16:35:00.221175+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 665, in _load_unlocked 2020-12-23T16:35:00.221175+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 678, in exec_module 2020-12-23T16:35:00.221176+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed 2020-12-23T16:35:00.221176+00:00 app[web.1]: File "/app/microblog.py", line 1, in <module> 2020-12-23T16:35:00.221176+00:00 app[web.1]: from app import create_app, db, cli 2020-12-23T16:35:00.221177+00:00 app[web.1]: File "/app/app/init.py", line 82 2020-12-23T16:35:00.221178+00:00 app[web.1]: else: 2020-12-23T16:35:00.221178+00:00 app[web.1]: ^ 2020-12-23T16:35:00.223813+00:00 app[web.1]: IndentationError: unindent does not match any outer indentation level

  • #147 Miguel Grinberg said 2020-12-23T23:16:23Z

    @Samyak: The error is clear, you have an identation error in line 82 of app/__init__.py.

  • #148 tony said 2021-03-02T14:05:00Z

    I deployed my app with "git push heroku master". My issue is how do I deploy only the commited changes made to the app instead of deploying the whole app to heroku.

    Note: I have a databse.db file, and whenever I run "git push heroku master" the local db file overides the db on heroku, how do I solve this issue.

  • #149 Miguel Grinberg said 2021-03-03T00:35:59Z

    @tony: you can't use a file based database with Heroku. Use Postgres, as shown in this article.

  • #150 Constantine Westerink said 2021-03-11T21:38:03Z

    Hey Miguel, how do i avoid database from reseting during the daily Hobby dyno restart.

Leave a Comment