Flask deprecated before_first_request how to update
Asked Answered
K

7

26

I'm learning web development for simple applications and I've created one that uses before_first_request decorator. According with the new release notes, the before_first_request is deprecated and will be removed from Flask 2.3:

Deprecated since version 2.2: Will be removed in Flask 2.3. Run setup code when creating the application instead.

I don't understand how I can update my code to be complacent with Flask 2.3 and still run a function at first request without using before_first_request. Could some kind soul give me an example?

Kelula answered 1/9, 2022 at 13:19 Comment(1)
switch to using the Application Factory Pattern and put whatever you did in the before_first_request into the init code of the Flask app. See this excellent guide on how to set up a Flask app using AFPCoumarone
P
36

I don't know if this is answered but for anyone looking for the answer:

in place of the @app.before_first_request decorated function use the app instance like this: i.e.

# In place of something like this
@app.before_first_request
def create_tables():
    db.create_all()
    ...

# push context manually to app
with app.app_context():
    db.create_all()
Plasma answered 30/11, 2022 at 14:48 Comment(6)
My code is executing twice within this (I'm just printing "hello, world"). Any ideas why this happens or how to fix it?Fifteenth
^ Fixed it. It was because my app was running with Debug=true, you'll have to set it to false so it doesn't run twice.Fifteenth
This gives me an error - "RuntimeError: Working outside of request context."Phenomenal
where exactly do you execute that with statement if using the application factory pattern?Contagious
this also works for quart but make sure to use asyncHierogram
Worked for me in Flask 3.0.3 - Thanks!Saponify
H
4

@app.before_first_request can be replicated simply with a single additional line of code to remove the handler from the app.

@app.before_request
def create_tables():
    # The following line will remove this handler, making it
    # only run on the first request
    app.before_request_funcs[None].remove(create_tables)

    db.create_all()
Hermitage answered 6/2 at 15:53 Comment(3)
This worked better than "with app.app_context():" for me because the code I am running attempts to call multiprocessing.Manager(). this will fail if the process is just starting, as it will be if "with app.app_context()" is running outside of a function. The pattern shown here allows process creation to finish and only calls my code when the first request comes inSynaeresis
It also won't slow down loading of the app in non-web contexts, such as in the CLI.Hermitage
Didn't work for me. I still get the same error Flask 3.0.3Saponify
S
1

We could manually track if the first request has been made before in a bool such as appHasRunBefore using the still available @app.before_request

appHasRunBefore:bool = False

@app.before_request
def firstRun():
    global appHasRunBefore
    if not appHasRunBefore:
        # Run any of your code here
        thread = threading.Thread(target=keep_alive, args=())
        thread.start()
        # Set the bool to True so this method isn't called again
        appHasRunBefore = True

We can then run any code if it is the first request.

Spirituality answered 10/1 at 18:57 Comment(1)
To follow best practices I renamed the global to _appHasRunBefore since this should be private for the module since its an implementation detail, but I like this solution more than the others.Dody
H
1

Use the Manually Push a Context approach:

app = Flask(__name__)

with app.app_context():
    # your code here to do things before first request
Heptode answered 23/6 at 13:54 Comment(0)
D
0

Use an alternative approach:

Instead of before_first_request You can use before_request along with a flag to ensure the code runs only once:

first_request = True

@app.before_request
def before_first_request():
    global first_request
    if first_request:
        # do your thing like create_db or whataver
        first_request = False

This worked for me, I am using Flask 3.0.3

Digitalin answered 31/7 at 17:18 Comment(0)
R
-1

In my case, I was using pytest to test the API and the package flask_monitoringdashboard to monitor my app performance, but the latest version of this last package uses the before_first_request method in the code.

The package team solved this issue one month ago in this commit, but they do not release a new version of the package until now.

  1. You can solve this problem manually by applying the upper commit to the package code.
  2. You can suppress the warning like the below:
import warnings
import flask_monitoringdashboard as monitoring_dashboard
from your_package import create_app()


app = create_app()
with warnings.catch_warnings():
    warnings.filterwarnings("ignore", category=DeprecationWarning)
    monitoring_dashboard.config.init_from(file=flask_monitoring_file_path)
    monitoring_dashboard.bind(app)
  1. If you are having this issue with pytest, try to not execute the code that binds the app with the dashboard in your tests, like not having the binding code in the create_app function.
Rolandrolanda answered 16/3, 2023 at 16:58 Comment(0)
C
-2
@app.before_first_request
def before_first_request():
    my_fun()

can be replaced with

app.before_request_funcs = [(None, my_fun())]

my_fun() will be run before any request.

Cuffs answered 28/8, 2023 at 12:28 Comment(1)
my_fun() will be run once, at the assignment of the variable and never again! But more, this runs EVERY request - the question wants to run once, on the FIRST request.Merlynmermaid

© 2022 - 2024 — McMap. All rights reserved.