One place for hosting & domains

      Flask

      How To Handle Errors in a Flask Application


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Flask is a lightweight Python web framework that provides useful tools and features for creating web applications in the Python Language.

      When you’re developing a web application, you will inevitably run into situations where your application behaves in a way contrary to what you expected. You might misspell a variable, misuse a for loop, or construct an if statement in a way that raises a Python exception, like calling a function before declaring it, or simply looking for a page that doesn’t exist. You’ll find it easier and smoother to develop your Flask applications if you learn how to handle errors and exceptions properly.

      In this tutorial, you’ll build a small web application that demonstrates how to handle common errors one encounters when developing a web application. You’ll create custom error pages, use the Flask debugger to troubleshoot exceptions, and use logging to track events in your application.

      Prerequisites

      Step 1 — Using The Flask Debugger

      In this step, you’ll create an application that has a few errors and run it without debug mode to see how the application responds. Then you’ll run it with debug mode on and use the debugger to troubleshoot application errors.

      With your programming environment activated and Flask installed, open a file called app.py for editing inside your flask_app directory:

      Add the following code inside the app.py file:

      flask_app/app.py

      from flask import Flask
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def index():
          return render_template('index.html')
      

      In the above code, you first import the Flask class from the flask package. Then you create a Flask application instance called app. You use the @app.route() decorator to create a view function called index(), which calls the render_template() function as the return value, which in turn renders a template called index.html. There are two errors in this code: the first is that you did not import the render_template() function, and the second one is that the index.html template file does not exist.

      Save and close the file.

      Next, inform Flask about the application using the FLASK_APP environment variable using the following command (on Windows, use set instead of export):

      Then run the application server using the flask run command:

      You will see the following information in your terminal:

      Output

      * Serving Flask app 'app' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

      This output provides the following information:

      • The Flask application being served (app.py in this case)
      • The environment, which is production here. The warning message stresses that this server is not for a production deployment. You’re using this server for development, so you can ignore this warning, but for more information, see the Deployment Options page on the Flask documentation. You can also check out this Flask deployment tutorial with Gunicorn, or this one with uWSGI, or you can use DigitalOcean App Platform to deploy your Flask application by following the How To Deploy a Flask App Using Gunicorn to App Platform tutorial.

      • The debug mode is off, which means that the Flask debugger is not running, and you won’t receive helpful error messages in your application. In a production environment, displaying detailed errors exposes your application to security vulnerabilities.

      • The server is running on the http://127.0.0.1:5000/ URL. To stop the server, use CTRL+C, but don’t do that just yet.

      Now, visit the index page using your browser:

      http://127.0.0.1:5000/
      

      You will see a message that looks like the following:

      Output

      Internal Server Error The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

      This is the 500 Internal Server Error, which is a server error response that indicates that the server encountered an internal error in the application code.

      In the terminal, you’ll see the following output:

      Output

      [2021-09-12 15:16:56,441] ERROR in app: Exception on / [GET] Traceback (most recent call last): File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app response = self.full_dispatch_request() File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request rv = self.dispatch_request() File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) File "/home/abd/python/flask/series03/flask_app/app.py", line 8, in index return render_template('index.html') NameError: name 'render_template' is not defined 127.0.0.1 - - [12/Sep/2021 15:16:56] "GET / HTTP/1.1" 500 -

      The traceback above goes through the code that triggered the internal server error. The line NameError: name 'render_template' is not defined gives the root cause of the problem: the render_template() function has not been imported.

      As you can see here, you have to go to the terminal to troubleshoot errors, which is not convenient.

      You can have a better troubleshooting experience by enabling the debug mode in your development server. To do so, stop the server with CTRL+C and set the environment variable FLASK_ENV to development, so you can run the application in development mode (which enables the debugger), using the following command (on Windows, use set instead of export):

      • export FLASK_ENV=development

      Run the development server:

      You’ll see an output similar to the following in the terminal:

      Output

      * Serving Flask app 'app' (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 120-484-907

      Here you see that the environment is now development, debug mode is on, and the debugger is active. The Debugger PIN is a PIN you need to unlock the console in your browser (an interactive python shell you can access by clicking the little terminal icon encircled in the image below).

      Refresh the index page on your browser and you’ll see the following page:

      The Flask Debugger

      Here, you see the error message displayed in a manner that’s easier to understand. The first heading gives you the name of the Python exception that caused the problem (NameError in this case). The second line gives you the direct reason (render_template() is not defined, which means it’s not imported in this case). Following that, you have the traceback going through the inner Flask code that was executed. Read the traceback from the bottom upward, because the last line in the traceback usually has the most useful information.

      Note:
      The circled terminal icon allows you to run Python code in the browser on different frames. This is useful for when you want to check the value of a variable the way you would do it in a Python interactive shell. When you click the terminal icon, you will need to type in the Debugger PIN code you got when you ran the server. You won’t need this interactive shell in this tutorial.

      To fix this NameError issue, leave the server running, open a new terminal window, activate your environment, and open your app.py file:

      Modify the file to look as follows:

      flask_app/app.py

      
      from flask import Flask, render_template
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def index():
          return render_template('index.html')
      

      Save and close the file.

      Here you imported the render_template() function that was missing.

      With the development server running, refresh the index page on your browser.

      This time you’ll see an error page with information that looks like so:

      Output

      jinja2.exceptions.TemplateNotFound jinja2.exceptions.TemplateNotFound: index.html

      This error message indicates that the index.html template does not exist.

      To fix this, you’ll create a base.html template file other templates will inherit from to avoid code repetition, then an index.html template that extends the base template.

      Create the templates directory, which is the directory where Flask looks for template files. Then open a base.html file using your favorite editor:

      • mkdir templates
      • nano templates/base.html

      Add the following code to your base.html file:

      flask_app/templates/base.html

      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>{% block title %} {% endblock %} - FlaskApp</title>
          <style>
              nav a {
                  color: #d64161;
                  font-size: 3em;
                  margin-left: 50px;
                  text-decoration: none;
              }
          </style>
      </head>
      <body>
          <nav>
              <a href="https://www.digitalocean.com/community/tutorials/{{ url_for('index') }}">FlaskApp</a>
              <a href="#">About</a>
          </nav>
          <hr>
          <div class="content">
              {% block content %} {% endblock %}
          </div>
      </body>
      </html>
      

      Save and close the file.

      This base template has all the HTML boilerplate you’ll need to reuse in your other templates. The title block will be replaced to set a title for each page, and the content block will be replaced with the content of each page. The navigation bar has two links, one for the index page where you use the url_for() helper function to link to the index() view function, and the other for an About page if you choose to include one in your application.

      Next, open a template file called index.html, which will inherit from the base template.

      • nano templates/index.html

      Add the following code to it:

      flask_app/templates/index.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Index {% endblock %}</h1>
          <h2>Welcome to FlaskApp!</h2>
      {% endblock %}
      

      Save and close the file.

      In the code above, you extend the base template and override the content block. You then set a page title and display it in an H1 header using the title block, and display a greeting in an H2 header.

      With the development server running, refresh the index page on your browser.

      You’ll see that the application displays no more errors and the index page is displayed as expected.

      You’ve now used debug mode and seen how to handle error messages. Next, you’ll abort a request to respond with an error message of your choice, and see how to respond with custom error pages.

      Step 2 — Creating Custom Error Pages

      In this step, you’ll learn how to abort requests and respond with a 404 HTTP error message for when the user requests data that does not exist on the server. You will also learn how to create custom error pages for common HTTP errors, such as the 404 Not Found error, and the 500 Internal Server Error error.

      To demonstrate how to abort requests and respond with a custom 404 HTTP error page, you’ll create a page that displays a few messages. If the requested message does not exist, you’ll respond with a 404 error.

      First, open your app.py file to add a new route for the messages page:

      Add the following route at the end of the file:

      flask_app/app.py

      # ...
      
      @app.route('/messages/<int:idx>')
      def message(idx):
          messages = ['Message Zero', 'Message One', 'Message Two']
          return render_template('message.html', message=messages[idx])
      

      Save and close the file.

      In the route above, you have a URL variable idx. This is the index that will determine what message will be displayed. For example, if the URL is /messages/0, the first message (Message Zero) will be displayed. You use the int converter to accept only positive integers, because URL variables have string values by default.

      Inside the message() view function, you have a regular Python list called messages with three messages. (In a real-world scenario, these messages would come from a database, an API, or another external data source.) The function returns a call to the render_template() function with two arguments, message.html as the template file, and a message variable that will be passed to the template. This variable will have a list item from the messages list depending on the value of the idx variable in the URL.

      Next open a new message.html template file:

      • nano templates/message.html

      Add the following code to it:

      flask_app/templates/message.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Messages {% endblock %}</h1>
          <h2>{{ message }}</h2>
      {% endblock %}
      

      Save and close the file.

      In the code above, you extend the base template and override the content block. You add a title (Messages) in an H1 heading, and display the value of the message variable in an H2 heading.

      With the development server running, visit the following URLs on your browser:

      http://127.0.0.1:5000/messages/0
      http://127.0.0.1:5000/messages/1
      http://127.0.0.1:5000/messages/2
      http://127.0.0.1:5000/messages/3
      

      You’ll see that the H2 contains the text Message Zero, Message One, or Message Two respectively on each one of the first three URLs. However, on the fourth URL, the server will respond with an IndexError: list index out of range error message. In a production environment, the response would’ve been a 500 Internal Server Error, but the proper response here is a 404 Not Found to indicate that the server can’t find a message with an index of 3.

      You can respond with a 404 error using Flask’s abort() helper function. To do so, open the app.py file:

      Edit the first line to import the abort() function. Then edit the message() view function by adding a try ... except clause as shown in the highlighted parts below:

      flask_app/app.py

      from flask import Flask, render_template, abort
      
      # ...
      # ...
      
      
      @app.route('/messages/<int:idx>')
      def message(idx):
          messages = ['Message Zero', 'Message One', 'Message Two']
          try:
              return render_template('message.html', message=messages[idx])
          except IndexError:
              abort(404)
      

      Save and close the file.

      In the code above, you import the abort() function, which you use to abort the request and respond with an error. In the message() view function, you use a try ... except clause to wrap the function. You first try to return the messages template with the message that corresponds to the index in the URL. If the index has no corresponding message, the IndexError exception will be raised. You then use the except clause to catch that error, and you use abort(404) to abort the request and respond with a 404 Not Found HTTP error.

      With the development server running, use your browser to revisit the URL that responded with an IndexError earlier (or visit any URL with an index greater than 2):

      http://127.0.0.1:5000/messages/3
      

      You will see the following response:

      Not Found
      
      The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
      

      You now have a better error message that indicates that the server could not find the requested message.

      Next, you’ll make a template for the 404 error page and one for the 500 error page.

      First, you’ll register a function with the special @app.errorhandler() decorator as a handler for the 404 error. Open the app.py file for editing:

      nano app.py
      

      Edit the file by adding the highlighted part as follows:

      flask_app/app.py

      from flask import Flask, render_template, abort
      
      app = Flask(__name__)
      
      
      @app.errorhandler(404)
      def page_not_found(error):
          return render_template('404.html'), 404
      
      
      @app.route('/')
      def index():
          return render_template('index.html')
      
      
      @app.route('/messages/<int:idx>')
      def message(idx):
          messages = ['Message Zero', 'Message One', 'Message Two']
          try:
              return render_template('message.html', message=messages[idx])
          except IndexError:
              abort(404)
      

      Save and close the file.

      Here you use the @app.errorhandler() decorator to register the function page_not_found() as a custom error handler. The function takes the error as an argument, and it returns a call to the render_template() function with a template called 404.html. You will create this template later, and you can use another name if you want. You also return the integer 404 after the render_template() call. This tells Flask that the status code in the response should be 404. If you don’t add it, the default status code response will be 200, which means that the request has succeeded.

      Next, open a new 404.html template:

      Add the following code to it:

      flask_app/templates/404.html

      {% extends 'base.html' %}
      
      {% block content %}
              <h1>{% block title %} 404 Not Found. {% endblock %}</h1>
              <p>OOPS! Sammy couldn't find your page; looks like it doesn't exist.</p>
              <p>If you entered the URL manually, please check your spelling and try again.</p>
      {% endblock %}
      

      Save and close the file.

      Just like any other template, you extend the base template, you replace the content of the content and title blocks, and you add your own HTML code. Here you have an <h1> heading as the title, a <p> tag with a custom error message telling the user the page was not found, and a helpful message for users who might have entered the URL manually.

      You can use whatever HTML, CSS, and JavaScript you want in your error pages in the same way you would in other templates.

      With the development server running, use your browser to revisit the following URL:

      http://127.0.0.1:5000/messages/3
      

      You’ll see the page now has the navigation bar that’s in the base template and the custom error message.

      Similarly, you can add a custom error page for your 500 Internal Server Error errors. Open the app.py file:

      Add the following error handler below the 404 error handler:

      flask_app/app.py

      # ...
      
      @app.errorhandler(404)
      def page_not_found(error):
          return render_template('404.html'), 404
      
      
      @app.errorhandler(500)
      def internal_error(error):
          return render_template('500.html'), 500
      
      # ...
      

      Here you use the same pattern as you did for the 404 error handler. You use the app.errorhandler() decorator with a 500 argument to make a function called internal_error() into an error handler. You render a template called 500.html, and respond with a status code of 500.

      Then to demonstrate how the custom error will be presented, add a route that responds with a 500 HTTP error at the end of the file. This route will always give a 500 Internal Server Error regardless of whether the debugger is running or not:

      flask_app/app.py

      
      # ...
      @app.route('/500')
      def error500():
          abort(500)
      

      Here you make a route /500 and use the abort() function to respond with a 500 HTTP error.

      Save and close the file.

      Next, open the new 500.html template:

      Add the following code to it:

      flask_app/templates/500.html

      {% extends 'base.html' %}
      
      {% block content %}
              <h1>{% block title %} 500 Internal Server Error {% endblock %}</h1>
              <p>OOOOPS! Something went wrong on the server.</p>
              <p>Sammy is currently working on this issue. Please try again later.</p>
      {% endblock %}
      

      Save and close the file.

      Here, you do the same thing you did with the 404.html template. You extend the base template, and replace the content block with a title and two custom messages informing the user about the internal server error.

      With the development server running, visit the route that responds with a 500 error:

      http://127.0.0.1:5000/500
      

      Your custom page will appear instead of the generic error page.

      You now know how to use custom error pages for HTTP errors in your Flask application. Next, you’ll learn how to use logging to track events in your application. Tracking events helps you understand how your code behaves, which in turn helps with development and troubleshooting.

      Step 3 — Using Logging to Track Events in Your Application

      In this step, you will use logging to track events that happen when the server is running and the application is being used, which helps you see what is going on in your application code so you can troubleshoot errors easier.

      You have already seen logs whenever the development server is running, which typically look like this:

      127.0.0.1 - - [21/Sep/2021 14:36:45] "GET /messages/1 HTTP/1.1" 200 -
      127.0.0.1 - - [21/Sep/2021 14:36:52] "GET /messages/2 HTTP/1.1" 200 -
      127.0.0.1 - - [21/Sep/2021 14:36:54] "GET /messages/3 HTTP/1.1" 404 -
      

      In these logs, you can see the following information:

      • 127.0.0.1: The host the server was running on.
      • [21/Sep/2021 14:36:45]: The date and time of the request.
      • GET: The HTTP request method. In this case, GET is used to retrieve data.
      • /messages/2: The path the user requested.
      • HTTP/1.1: The HTTP version.
      • 200 or 404: The status code of the response.

      These logs help you diagnose problems that occur in your application. You can log more information when you want to know more details about certain requests using the logger app.logger Flask provides.

      With logging, you can use different functions to report information on different logging levels. Each level indicates an event happened with a certain degree of severity. The following functions can be used:

      • app.logger.debug(): For detailed information about the event.
      • app.logger.info(): Confirmation that things are working as expected.
      • app.logger.warning(): Indication that something unexpected happened (such as “disk space low”), but the application is working as expected.
      • app.logger.error(): An error occurred in some part of the application.
      • app.logger.critical(): A critical error; the entire application might stop working.

      To demonstrate how to use the Flask logger, open your app.py file for editing to log a few events:

      Edit the message() view function to look as follows:

      flask_app/app.py

      
      # ...
      
      @app.route('/messages/<int:idx>')
      def message(idx):
          app.logger.info('Building the messages list...')
          messages = ['Message Zero', 'Message One', 'Message Two']
          try:
              app.logger.debug('Get message with index: {}'.format(idx))
              return render_template('message.html', message=messages[idx])
          except IndexError:
              app.logger.error('Index {} is causing an IndexError'.format(idx))
              abort(404)
      
      # ...
      

      Save and close the file.

      Here, you logged a few events on different levels. You use app.logger.info() to log an event that’s working as expected (which is an INFO level). You use app.logger.debug() for detailed information (DEBUG level), mentioning that the application is now getting a message with a specific index. Then you use app.logger.error() to log the fact that an IndexError exception has been raised with the specific index that caused the issue (ERROR level, because an error occurred).

      Visit the following URL:

      http://127.0.0.1:5000/messages/1
      

      You’ll see the following information in the terminal where your server is running:

      Output

      [2021-09-21 15:17:02,625] INFO in app: Building the messages list... [2021-09-21 15:17:02,626] DEBUG in app: Get message with index: 1 127.0.0.1 - - [21/Sep/2021 15:17:02] "GET /messages/1 HTTP/1.1" 200 -

      Here you see the INFO message app.logger.info() logs, and the DEBUG message with the index number that you logged using app.logger.debug().

      Now visit a URL for a message that does not exist:

      http://127.0.0.1:5000/messages/3
      

      You’ll see the following information in the terminal:

      Output

      [2021-09-21 15:33:43,899] INFO in app: Building the messages list... [2021-09-21 15:33:43,899] DEBUG in app: Get message with index: 3 [2021-09-21 15:33:43,900] ERROR in app: Index 3 is causing an IndexError 127.0.0.1 - - [21/Sep/2021 15:33:43] "GET /messages/3 HTTP/1.1" 404 -

      As you can see, you have INFO and DEBUG logs that you’ve seen before, and a new ERROR log because a message with an index of 3 does not exist.

      Logging events, detailed information, and errors helps you identify where something went wrong and makes troubleshooting easier.

      You’ve learned in this step how to use the Flask logger. Check out How To Use Logging in Python 3 for a better understanding of logging. For an in-depth look at logging, see the Flask logging documentation and the Python documentation for logging.

      Conclusion

      You now know how to use debug mode in Flask, and how to troubleshoot and fix some common errors you may encounter when developing a Flask web application. You’ve also created custom error pages for common HTTP errors, and you’ve used the Flask logger to track events in your application to help you inspect and figure out how your application behaves.

      If you would like to read more about Flask, check out the Flask topic page.



      Source link

      How To Use Templates in a Flask Application


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Flask is a lightweight Python web framework that provides useful tools and features for creating web applications in the Python Language.

      When developing a web application, it is important to separate business logic from presentation logic. Business logic is what handles user requests and talks to the database to build an appropriate response. Presentation logic is how the data is presented to the user, typically using HTML files to build the basic structure of the response web page, and CSS styles to style HTML components. For example, in a social media application, you might have a username field and a password field that can be displayed only when the user is not logged in. If the user is logged in, you display a logout button instead. This is the presentation logic. If a user types in their username and password, you can use Flask to perform business logic: You extract the data (the username and password) from the request, log the user in if the credentials are correct or respond with an error message. How the error message is displayed will be handled by the presentation logic.

      In Flask, you can use the Jinja templating language to render HTML templates. A template is a file that can contain both fixed and dynamic content. When a user requests something from your application (such as an index page, or a login page), Jinja allows you to respond with an HTML template where you can use many features that are not available in standard HTML, such as variables, if statements, for loops, filters, and template inheritance. These features allow you to efficiently write easy-to-maintain HTML pages. Jinja also automatically escapes HTML to prevent Cross-Site Scripting (XSS) attacks.

      In this tutorial, you’ll build a small web application that renders several HTML files. You’ll use variables to pass data from the server to the templates. Template inheritance will help you avoid repetition. You’ll use logic in templates such as conditionals and loops, use filters to modify text, and use the Bootstrap toolkit to style your application.

      Prerequisites

      Step 1 — Rendering a Template and Using Variables

      Make sure you have activated your environment and have Flask installed, and then you can start building your application. The first step is to display a message that greets visitors on the index page. You’ll use Flask’s render_template() helper function to serve an HTML template as the response. You will also see how to pass variables from your application side to your templates.

      First, in your flask_app directory, open a file named app.py for editing. Use nano or your favorite text editor:

      Add the following code inside the app.py file:

      flask_app/app.py

      
      from flask import Flask, render_template
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def hello():
          return render_template('index.html')
      

      Save and close the file.

      In this code block, you import the Flask class and the render_template() function from the flask package. You use the Flask class to create your Flask application instance named app. Then you define a view function (which is a Python function that returns an HTTP response) called hello() using the app.route() decorator, which converts a regular function into a view function. This view function uses the render_template() function to render a template file called index.html.

      Next, you’ll have to create the index.html template file in a directory called templates inside your flask_app directory. Flask looks for templates in the templates directory, which is called templates, so the name is important. Make sure you’re inside the flask_app directory and run the following command to create the templates directory:

      Next, open a file called index.html inside the templates directory for editing. The name index.html here is not a standard required name; you can call it home.html or homepage.html or anything else if you want:

      • nano templates/index.html

      Add the following HTML code inside the index.html file:

      flask_app/templates/index.html

      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>FlaskApp</title>
      </head>
      <body>
          <h1>Hello World!</h1>
          <h2>Welcome to FlaskApp!</h2>
      </body>
      </html>
      

      Here, you set a title, added a Hello World! message as an H1 heading, and created a Welcome to FlaskApp! message as an H2 heading.

      Save and close the file.

      While in your flask_app directory with your virtual environment activated, tell Flask about the application (app.py in your case) using the FLASK_APP environment variable, and set the FLASK_ENV environment variable to development to run the application in development mode and get access to the debugger. Use the following commands to do this (on Windows, use set instead of export):

      • export FLASK_APP=app
      • export FLASK_ENV=development

      Then, run the application using the flask run command:

      With the development server running, visit the following URL using your browser:

      http://127.0.0.1:5000/
      

      You’ll see the title of the page is set to FlaskApp, and the two headings are rendered HTML.

      In web applications, you often need to pass data from your application’s Python files to your HTML templates. To demonstrate how to do this in this application, you will pass a variable containing the current UTC date and time to the index template, and you’ll display the value of the variable in the template.

      Leave the server running, and open your app.py file for editing in a new terminal:

      Import the datetime module from the Python standard library and edit the index() function so the file looks as follows:

      flask_app/app.py

      import datetime
      from flask import Flask, render_template
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def hello():
          return render_template('index.html"https://www.digitalocean.com/community/tutorials/, utc_dt=datetime.datetime.utcnow())
      

      Save and close the file.

      Here you imported the datetime module and passed a variable called utc_dt to the index.html template with the value of datetime.datetime.utcnow(), which is the current UTC date and time.

      Next, to display the variable’s value on the index page, open the index.html file for editing:

      • nano templates/index.html

      Edit the file to look as follows:

      flask_app/templates/index.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>FlaskApp</title>
      </head>
      <body>
          <h1>Hello World!</h1>
          <h2>Welcome to FlaskApp!</h2>
          <h3>{{ utc_dt }}</h3>
      </body>
      </html>
      

      Save and close the file.

      You added an H3 heading with the special {{ ... }} delimiter to print the value of the utc_dt variable.

      Open your browser and visit the index page:

      http://127.0.0.1:5000/
      

      You’ll see a page similar to the following image:

      The Index Page

      You’ve now created an index page with an HTML template in your Flask application, rendered a template, and passed and displayed a variable value. Next you’ll avoid code repetition by using template inheritance.

      Step 2 — Using Template Inheritance

      In this step, you’ll make a base template with content that can be shared with your other templates. You’ll edit your index template to inherit from the base template. Then, you’ll make a new page that will serve as your application’s About page, where users can find more information about your application.

      A base template contains HTML components that are typically shared between all other templates, such as the application’s title, navigation bars, and footers.

      First, open a new file called base.html for editing inside your templates directory:

      Write the following code inside your base.html file:

      flask_app/templates/base.html

      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>{% block title %} {% endblock %} - FlaskApp</title>
          <style>
              nav a {
                  color: #d64161;
                  font-size: 3em;
                  margin-left: 50px;
                  text-decoration: none;
              }
          </style>
      </head>
      <body>
          <nav>
              <a href="#">FlaskApp</a>
              <a href="#">About</a>
          </nav>
          <hr>
          <div class="content">
              {% block content %} {% endblock %}
          </div>
      </body>
      </html>
      

      Save and close the file.

      Most of the code in this file is standard HTML, a title, some styling for the navigation links, a navigation bar with two links, one for the index page and one for the About page not yet created, and a <div> for the page’s content. (The links don’t work yet; the next step will demonstrate how to link between pages).

      However, the following highlighted parts are specific to the Jinja template engine:

      • {% block title %} {% endblock %}: A block that serves as a placeholder for a title. You’ll later use it in other templates to provide a custom title for each page in your application without rewriting the entire <head> section each time.

      • {% block content %} {% endblock %}: Another block that will be replaced by content depending on the child template (a template that inherits from base.html) that will override it.

      Now that you have a base template, you can take advantage of it using inheritance. Open the index.html file:

      • nano templates/index.html

      Then replace its contents with the following:

      flask_app/templates/index.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Index {% endblock %}</h1>
          <h1>Hello World!</h1>
          <h2>Welcome to FlaskApp!</h2>
          <h3>{{ utc_dt }}</h3>
      {% endblock %}
      

      Here, you use the {% extends %} tag to inherit from the base.html template. You then extend it via replacing the content block in the base template with what is inside the content block in the preceding code block.

      This content block contains an <h1> tag with the text Index inside a title block, which in turn replaces the original title block in the base.html template with the text Index so that the complete title becomes Index - FlaskApp. This way, you can avoid repeating the same text twice, as it works both as a title for the page and a heading that appears below the navigation bar inherited from the base template.

      Then you have a few more headings: one <h1> heading with the text Hello World!, an <h2> heading, and an <h3> heading containing the value of the utc_dt variable.

      Template inheritance gives you the ability to reuse the HTML code you have in other templates (base.html in this case) without having to repeat it each time it is needed.

      Save and close the file and refresh the index page on your browser. The page will look as follows:

      The Index Page After Inheritance

      Next, you’ll create the About page. Open the app.py file to add a new route:

      Add the following route at the end of the file:

      flask_app/app.py

      
      # ...
      @app.route('/about/')
      def about():
          return render_template('about.html')
      

      Here you use the app.route() decorator to create a view function called about(). In it, you return the result of calling the render_template() function with the about.html template file name as an argument.

      Save and close the file.

      Open a template file called about.html for editing:

      • nano templates/about.html

      Add the following code to the file:

      flask_app/templates/about.html

      
      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} About {% endblock %}</h1>
          <h3>FlaskApp is a Flask web application written in Python.</h3>
      {% endblock %}
      

      Here, you inherit from the base template using the extends tag, replace the base template’s content block with an <h1> tag that also serves as the page’s title, and add an <h3> tag with some information about the application.

      Save and close the file.

      With the development server running, visit the following URL using your browser:

      http://127.0.0.1:5000/about
      

      You’ll see a page similar to the following:

      About Page

      Notice how the navigation bar and part of the title are inherited from the base template.

      You’ve now created a base template and used it in your index page and about page to avoid code repetition. The links in the navigation bar don’t do anything at this point. In the next step, you’ll learn how to link between routes in your templates by fixing the navigation bar links.

      Step 3 — Linking between Pages

      In this step, you’ll learn how to link between pages in your templates using the url_for() helper function. You will add two links to the navigation bar in your base template, one for the index page, and one for the About page.

      First open your base template for editing:

      Edit the file to look as follows:

      flask_app/templates/base.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>{% block title %} {% endblock %} - FlaskApp</title>
          <style>
              nav a {
                  color: #d64161;
                  font-size: 3em;
                  margin-left: 50px;
                  text-decoration: none;
              }
          </style>
      </head>
      <body>
          <nav>
              <a href="https://www.digitalocean.com/community/tutorials/{{ url_for('hello') }}">FlaskApp</a>
              <a href="https://www.digitalocean.com/community/tutorials/{{ url_for('about') }}">About</a>
          </nav>
          <hr>
          <div class="content">
              {% block content %} {% endblock %}
          </div>
      </body>
      </html>
      

      Here, you use the special url_for() function that will return the URL for the view function you give it. The first link links to the route of the hello() view function (which is the index page). The second link links to the route of the about() view function. Notice that you pass the name of the view function, not the route (/ or /about).

      Using the url_for() function to build URLs helps you manage URLs better. If you hard-code URLs, your links will break if you edit the routes. With url_for() you can edit routes and guarantee that the links will still work as expected. The url_for() function also takes care of other things like escaping special characters.

      Save and close the file.

      Now go to the index page and try out the links in the navigation bar. You’ll see that they work as expected.

      You learned how to use the url_for() function to link to other routes in your templates. Next, you will add some conditional statements to control what is displayed in your templates depending on conditions you set, and use for loops in your templates to display list items.

      Step 4 — Using Conditionals and Loops

      In this step, you’ll use if statements in your templates to control what to display depending on certain conditions. You’ll also use for loops to go through Python lists and display each item in the list. You’ll add a new page that displays comments in a list. Comments with an even index number will have a blue background, and comments with an odd index number will be displayed with a gray background.

      First, you will create a route for the comments page. Open your app.py file for editing:

      Add the following route at the end of the file:

      flask_app/app.py

      
      # ...
      
      @app.route('/comments/')
      def comments():
          comments = ['This is the first comment.',
                      'This is the second comment.',
                      'This is the third comment.',
                      'This is the fourth comment.'
                      ]
      
          return render_template('comments.html', comments=comments)
      

      In the route above, you have a Python list called comments that contains four items. (These comments would usually come from a database in a real-world scenario rather than being hard-coded like you’ve done here.) You return a template file called comments.html in the last line, passing a variable called comments containing the list to the template file.

      Save and close the file.

      Next, open a new comments.html file inside the templates directory for editing:

      • nano templates/comments.html

      Add the following code to the file:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
              <div style="padding: 10px; background-color: #EEE; margin: 20px">
                  <p style="font-size: 24px">{{ comment }}</p>
              </div>
              {% endfor %}
          </div>
      {% endblock %}
      

      Here, you extend the base.html template and replace the contents of the content block. First, you use an <h1> heading that also serves as the page’s title.

      You use a Jinja for loop in the line {% for comment in comments %} to go through each comment in the comments list (which gets stored in the comment variable). You display the comment in the <p style="font-size: 24px">{{ comment }}</p> tag the same way you would normally display a variable in Jinja. You signal the ending of the for loop using the {% endfor %} keyword. This is different from the way Python for loops are constructed because there is no special indentation in Jinja templates.

      Save and close the file.

      With the development server running, open your browser and visit the comments page:

      http://127.0.0.1:5000/comments
      

      You will see a page similar to the following:

      Comments Page

      Now you will use the if conditional statement in your templates by displaying comments with an odd index number with a gray background, and comments with an even index number with a blue background.

      Open your comments.html template file for editing:

      • nano templates/comments.html

      Edit it to look as follows:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  {% if loop.index % 2 == 0 %}
                      {% set bg_color="#e6f9ff" %}
                  {% else %}
                      {% set bg_color="#eee" %}
                  {% endif %}
      
                  <div style="padding: 10px; background-color: {{ bg_color }}; margin: 20px">
                      <p>#{{ loop.index }}</p>
                      <p style="font-size: 24px">{{ comment }}</p>
                  </div>
              {% endfor %}
          </div>
      {% endblock %}
      

      With this new edit, you added an if statement in the line {% if loop.index % 2 == 0 %}. The loop variable is a special Jinja variable that gives you access to information about the current loop. Here you use loop.index to get the index of the current item, which starts from 1, not 0 as in Python lists.

      The if statement here checks whether the index is even using the % operator. It checks for the remainder of dividing the index number by 2; if the remainder is 0 it means the index number is even, otherwise, the index number is odd. You use the {% set %} tag to declare a variable called bg_color. If the index number is even, you set it to a blueish color, otherwise, if the index number is odd, you set the bg_color variable to gray. You then use the bg_color variable to set a background color for the <div> tag that contains the comment. Above the comment’s text, you use loop.index to display the current index number in a <p> tag.

      Save and close the file.

      Open your browser and visit the comments page:

      http://127.0.0.1:5000/comments
      

      You will see your new Comments page:

      Comments Page With Alternating Background Colors

      This was a demonstration of how to use the if statement. But you can also achieve the same effect by using the special loop.cycle() Jinja helper. To demonstrate this, open the comments.html file:

      • nano templates/comments.html

      Edit it to look as follows:

      flask_app/templates/comments.html

      
      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  <div style="padding: 10px;
                              background-color: {{ loop.cycle('#EEE', '#e6f9ff') }};
                              margin: 20px">
                      <p>#{{ loop.index }}</p>
                      <p style="font-size: 24px">{{ comment }}</p>
                  </div>
              {% endfor %}
          </div>
      {% endblock %}
      

      Here, you removed the if/else statement and used the loop.cycle('#EEE', '#e6f9ff') helper to cycle between the two colors. The value of background-color will be #EEE one time and #e6f9ff another.

      Save and close the file.

      Open the comments page in your browser, refresh it, and you’ll see that this has the same effect as the if statement.

      You can use if statements for multiple purposes, including controlling what gets displayed on the page. For example, to display all comments except for the second one, you can use an if statement with the condition loop.index != 2 to filter out the second comment.

      Open the comments template:

      • nano templates/comments.html

      And edit it to look as follows:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  {% if loop.index != 2 %}
                      <div style="padding: 10px;
                                  background-color: #EEE;
                                  margin: 20px">
                          <p>#{{ loop.index }}</p>
                          <p style="font-size: 24px">{{ comment }}</p>
                      </div>
                  {% endif %}
              {% endfor %}
          </div>
      {% endblock %}
      

      Here, you use {% if loop.index != 2 %} to show only the comments that don’t have the index 2, which means all the comments except for the second one. You also use a hard-coded value for the background color instead of the loop.cycle() helper to make things simpler, and the rest is not changed. You end the if statement using {% endif %}.

      Save and close the file.

      Refresh the comments page and you’ll see that the second comment is not displayed.

      You now need to add a link that takes users to the Comments page in the navigation bar. Open the base template for editing:

      Edit the contents of the <nav> tag by adding a new <a> link to it:

      flask_app/templates/base.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>{% block title %} {% endblock %} - FlaskApp</title>
          <style>
              nav a {
                  color: #d64161;
                  font-size: 3em;
                  margin-left: 50px;
                  text-decoration: none;
              }
          </style>
      </head>
      <body>
          <nav>
              <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("hello') }}">FlaskApp</a>
              <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("comments') }}">Comments</a>
              <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("about') }}">About</a>
          </nav>
          <hr>
          <div class="content">
              {% block content %} {% endblock %}
          </div>
      </body>
      </html>
      

      Here, you use the url_for() helper to link to the comments() view function.

      Save and close the file.

      The navigation bar will now have a new link that links to the comments page.

      You used if statements in your templates to control what to display depending on certain conditions. You used for loops to go through Python lists and display each item in the list, and you learned about the special loop variable in Jinja. Next, you’ll use Jinja filters to control how variable data is displayed.

      Step 5 — Using Filters

      In this step, you’ll learn how to use Jinja filters in your templates. You’ll use the upper filter to convert comments you added in the previous step to uppercase, you’ll use the join filter to join a sequence of strings into one string, and you’ll learn how to render trusted HTML code without escaping it using the safe filter.

      First, you will convert the comments in the comments page to uppercase. Open the comments.html template for editing:

      • nano templates/comments.html

      Edit it to look as follows:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  {% if loop.index != 2 %}
                      <div style="padding: 10px;
                                  background-color: #EEE;
                                  margin: 20px">
                          <p>#{{ loop.index }}</p>
                          <p style="font-size: 24px">{{ comment | upper }}</p>
                      </div>
                  {% endif %}
              {% endfor %}
          </div>
      {% endblock %}
      

      Here, you added the upper filter using the pipe symbol (|). This will modify the value of the comment variable to be uppercase.

      Save and close the file.

      With the development server running, open the comments page with your browser:

      http://127.0.0.1:5000/comments
      

      You can see that the comments are all in uppercase after applying the filter.

      Filters can also take arguments in parentheses. To demonstrate this, you’ll use the join filter to join all the comments in the comments list.

      Open the comments template:

      • nano templates/comments.html

      Edit it to look as follows:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  {% if loop.index != 2 %}
                      <div style="padding: 10px;
                                  background-color: #EEE;
                                  margin: 20px">
                          <p>#{{ loop.index }}</p>
                          <p style="font-size: 24px">{{ comment | upper }}</p>
                      </div>
                  {% endif %}
              {% endfor %}
              <hr>
              <div>
                  <p>{{ comments | join(" | ") }}</p>
              </div>
          </div>
      {% endblock %}
      

      Here you added an <hr> tag and a <div> tag where you join all the comments in the comments list using the join() filter.

      Save and close the file.

      Refresh the comments page and you’ll see a page similar to the following:

      Comments Page With Join Filter

      As you can see, the comments list is displayed with the comments separated by a pipe symbol, which is what you passed to the join() filter.

      Another important filter is the safe filter, which allows you to render trusted HTML on the browser. To illustrate this, you’ll add some text containing an HTML tag to your comments template using the {{ }} Jinja delimiter. In a real-world scenario, this would come as a variable from the server. Then you’ll edit the join() argument to be the <hr> tag instead of the pipe symbol.

      Open the comments template:

      • nano templates/comments.html

      Edit it to look as follows:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  {% if loop.index != 2 %}
                      <div style="padding: 10px;
                                  background-color: #EEE;
                                  margin: 20px">
                          <p>#{{ loop.index }}</p>
                          <p style="font-size: 24px">{{ comment | upper }}</p>
                      </div>
                  {% endif %}
              {% endfor %}
              <hr>
              <div>
                  {{ "<h1>COMMENTS</h1>" }}
                  <p>{{ comments | join("https://www.digitalocean.com/community/tutorials/ <hr> ") }}</p>
              </div>
          </div>
      {% endblock %}
      

      Here, you added the value "<h1>COMMENTS</h1>" and changed the join argument to the <hr> tag.

      Save and close the file.

      Refresh the comments page and you’ll see a page similar to the following:

      Comments Page With No Safe Filter

      As you can see, the HTML tags were not rendered. This is a safety feature in Jinja, because some HTML tags can be harmful and may result in a Cross Site Scripting (XSS) attack. You should allow only trusted HTML to be rendered in the browser.

      To render the HTML tags above, open the comments template file:

      • nano templates/comments.html

      Edit it by adding the safe filter:

      flask_app/templates/comments.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Comments {% endblock %}</h1>
          <div style="width: 50%; margin: auto">
              {% for comment in comments %}
                  {% if loop.index != 2 %}
                      <div style="padding: 10px;
                                  background-color: #EEE;
                                  margin: 20px">
                          <p>#{{ loop.index }}</p>
                          <p style="font-size: 24px">{{ comment | upper }}</p>
                      </div>
                  {% endif %}
              {% endfor %}
              <hr>
              <div>
                  {{ "<h1>COMMENTS</h1>"https://www.digitalocean.com/community/tutorials/ | safe }}
                  <p>{{ comments | join(" <hr> ") | safe }}</p>
              </div>
          </div>
      {% endblock %}
      

      You can see that you can also chain filters like in the line <p>{{ comments | join(" <hr> ") | safe }}</p>. Each filter gets applied to the result of the previous filtering.

      Save and close the file.

      Refresh the comments page and you’ll see that the HTML tags are now rendered as expected:

      Comments Page With Safe Filter

      Warning: Using the safe filter on HTML from unknown data sources may open up your application to XSS attacks. Do not use it unless the HTML you are rendering is from a trusted source.

      For more information, check out the list of built-in Jinja filters.

      You have now learned how to use filters in your Jinja templates to modify variable values. Next, you’ll integrate the Bootstrap toolkit to style your application.

      Step 6 — Integrating Bootstrap

      In this step, you’ll learn how to use the Bootstrap toolkit to style your application. You’ll add a Bootstrap navigation bar in the base template that will appear in all the pages that inherit from the base template.

      The Bootstrap toolkit helps you style your application so it is more visually appealing. It will also help you incorporate responsive web pages in your web application so that it works well on mobile browsers without writing your own HTML, CSS, and JavaScript code to achieve these goals.

      To use Bootstrap, you’ll need to add it to the base template so you can use it in all other templates.

      Open your base.html template, for editing:

      Edit it to look as follows:

      flask_app/templates/base.html

      <!doctype html>
      <html lang="en">
        <head>
          <!-- Required meta tags -->
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
      
          <!-- Bootstrap CSS -->
          <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
      
          <title>{% block title %} {% endblock %} - FlaskApp</title>
        </head>
        <body>
          <nav class="navbar navbar-expand-lg navbar-light bg-light">
          <div class="container-fluid">
              <a class="navbar-brand" href="https://www.digitalocean.com/community/tutorials/{{ url_for("hello') }}">FlaskApp</a>
              <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
              <span class="navbar-toggler-icon"></span>
              </button>
              <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav">
                  <li class="nav-item">
                    <a class="nav-link" href="https://www.digitalocean.com/community/tutorials/{{ url_for("comments') }}">Comments</a>
                  </li>
                  <li class="nav-item">
                    <a class="nav-link" href="https://www.digitalocean.com/community/tutorials/{{ url_for("about') }}">About</a>
                  </li>
              </ul>
              </div>
          </div>
          </nav>
          <div class="container">
              {% block content %} {% endblock %}
          </div>
      
          <!-- Optional JavaScript -->
      
          <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
      
        </body>
      </html>
      

      Most of the code above is Bootstrap boilerplate required to use it. You have some meta tags, a link to the Bootstrap CSS file in the <head> section, and at the bottom you have a link to optional JavaScript. The highlighted parts of the code contain Jinja code explained in the previous steps. Notice how you use specific tags and CSS classes to tell Bootstrap how to display each element.

      In the <nav> tag above, you have an <a> tag with the class navbar-brand, which determines the brand link in the navigation bar. Inside the <ul class="navbar-nav"> tag, you have regular navigation bar items inside an <a> tag in an <li> tag.

      To learn more about these tags and CSS classes, see the Bootstrap components.

      Save and close the file.

      With the development server running, open the index page with your browser:

      http://127.0.0.1:5000/
      

      You’ll see a page similar to the following:

      Index Page with Bootstrap

      You can now use Bootstrap components to style items in your Flask application in all of your templates.

      Conclusion

      You now know how to use HTML templates in your Flask web application. You’ve used variables to pass data from the server to templates, employed template inheritance to avoid repetition, incorporated elements such as if conditionals and for loops, and linked between different pages. You learned about filters to modify text and display trusted HTML, and you integrated Bootstrap into your application.

      If you would like to read more about Flask, check out the Flask topic page.



      Source link

      How To Create Your First Web Application Using Flask and Python 3


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Flask is a lightweight Python web framework that provides useful tools and features for creating web applications in the Python Language. It gives developers flexibility and is an accessible framework for new developers because you can build a web application quickly using only a single Python file. Flask is also extensible and doesn’t force a particular directory structure or require complicated boilerplate code before getting started.

      Learning Flask will allow you to quickly create web applications in Python. You can take advantage of Python libraries to add advanced features to your web application, like storing your data in a database, or validating web forms.

      In this tutorial, you’ll build a small web application that renders HTML text on the browser. You’ll install Flask, write and run a Flask application, and run the application in development mode. You’ll use routing to display various web pages that serve different purposes in your web application. You’ll also use view functions to allow users to interact with the application through dynamic routes. Finally, you’ll use the debugger to troubleshoot errors.

      Prerequisites

      Step 1 — Installing Flask

      In this step, you’ll activate your Python environment and install Flask using the pip package installer.

      First, activate your programming environment if you haven’t already:

      Once you have activated your programming environment, install Flask using the pip install command:

      Once the installation is complete, you will see a list of installed packages in the last parts of the output, similar to the following:

      Output

      ... Installing collected packages: Werkzeug, MarkupSafe, Jinja2, itsdangerous, click, flask Successfully installed Jinja2-3.0.1 MarkupSafe-2.0.1 Werkzeug-2.0.1 click-8.0.1 flask-2.0.1 itsdangerous-2.0.1

      This means that installing Flask also installed several other packages. These packages are dependencies Flask needs to perform different functions.

      You’ve created the project folder, a virtual environment, and installed Flask. You can now move on to setting up a simple application.

      Step 2 — Creating a Simple Application

      Now that you have your programming environment set up, you’ll start using Flask. In this step, you’ll make a small Flask web application inside a Python file, in which you’ll write HTML code to display on the browser.

      In your flask_app directory, open a file named app.py for editing, use nano or your favorite text editor:

      Write the following code inside the app.py file:

      flask_app/app.py

      
      from flask import Flask
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def hello():
          return '<h1>Hello, World!</h1>'
      

      Save and close the file.

      In the above code block, you first import the Flask object from the flask package. You then use it to create your Flask application instance, giving it the name app. You pass the special variable __name__, which holds the name of the current Python module. This name tells the instance where it’s located; you need this because Flask sets up some paths behind the scenes.

      Once you create the app instance, you can use it to handle incoming web requests and send responses to the user. @app.route is a decorator that turns a regular Python function into a Flask view function, which converts the function’s return value into an HTTP response to be displayed by an HTTP client, such as a web browser. You pass the value '/' to @app.route() to signify that this function will respond to web requests for the URL /, which is the main URL.

      The hello() view function returns the string '<h1>Hello, World!</h1>' as an HTTP response.

      You now have a simple Flask application in a Python file called app.py, in the next step, you will run the application to see the result of the hello() view function rendered in a web browser.

      Step 3 — Running the Application

      After creating the file that contains the Flask application, you’ll run it using the Flask command line interface to start the development server and render on the browser the HTML code you wrote as a return value for the hello() view function in the previous step.

      First, while in your flask_app directory with your virtual environment activated, tell Flask where to find the application (app.py in your case) using the FLASK_APP environment variable with the following command (on Windows, use set instead of export):

      Then specify that you want to run the application in development mode (so you can use the debugger to catch errors) with the FLASK_ENV environment variable:

      • export FLASK_ENV=development

      Lastly, run the application using the flask run command:

      Once the application is running, the output will be something like this:

      Output

      * Serving Flask app "app" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 296-353-699

      The preceding output has several pieces of information, such as:

      • The name of the application you’re running ("app").
      • The environment in which the application is being run (development).
      • Debug mode: on signifies that the Flask debugger is running. This is useful when developing because it provides detailed error messages when things go wrong, which makes troubleshooting easier.
      • The application is running locally on the URL http://127.0.0.1:5000/. 127.0.0.1 is the IP that represents your machine’s localhost and :5000 is the port number.

      Open a browser and type in the URL http://127.0.0.1:5000/. You will see the text Hello, World! in an <h1> heading as a response. This confirms that your application is successfully running.

      If you want to stop the development server, press CTRL+C.

      Warning: Flask uses a simple web server to serve your application in a development environment, which also means that the Flask debugger is running to make catching errors easier. You should not use this development server in a production deployment. See the Deployment Options page on the Flask documentation for more information. You can also check out this Flask deployment tutorial with Gunicorn or this one with uWSGI or you can use DigitalOcean App Platform to deploy your Flask application by following the How To Deploy a Flask App Using Gunicorn to App Platform tutorial.

      To continue developing the app.py application, leave the development server running and open another terminal window. Move into the flask_app directory, activate the virtual environment, set the environment variables FLASK_ENV and FLASK_APP, and continue to the next steps. (These commands are listed earlier in this step.)

      Note: When opening a new terminal, or when you close the one you are running the development server on and want to rerun it, it is important to remember activating the virtual environment and setting the environment variables FLASK_ENV and FLASK_APP for the flask run command to work properly.

      You only need to run the server once in one terminal window.

      While a Flask application’s development server is already running, it is not possible to run another Flask application with the same flask run command. This is because flask run uses the port number 5000 by default, and once it is taken, it becomes unavailable to run another application on so you would receive an error similar to the following:

      Output

      OSError: [Errno 98] Address already in use

      To solve this problem, either stop the server that’s currently running via CTRL+C, then run flask run again, or if you want to run both applications at the same time, you can pass a different port number to the -p argument, for example, to run another application on port 5001 use the following command:

      With this you can have one application running on http://127.0.0.1:5000/ and another one on http://127.0.0.1:5001/ if you want to.

      You now have a small Flask web application. You’ve run your application and displayed information on the web browser. Next, you’ll learn about routes and how to use them to serve multiple web pages.

      Step 4 — Routes and View Functions

      In this step, you’ll add a few routes to your application to display different pages depending on the requested URL. You’ll also learn about view functions and how to use them.

      A route is a URL you can use to determine what the user receives when they visit your web application on their browser. For example, http://127.0.0.1:5000/ is the main route that might be used to display an index page. The URL http://127.0.0.1:5000/about may be another route used for an about page that gives the visitor some information about your web application. Similarly, you can create a route that allows users to sign in to your application at http://127.0.0.1:5000/login.

      Your Flask application currently has one route that serves users who request the main URL (http://127.0.0.1:5000/). To demonstrate how to add a new web page to your application, you will edit your application file to add another route that provides information on your web application at http://127.0.0.1:5000/about.

      First, open your app.py file for editing:

      Edit the file by adding the following highlighted code at the end of the file:

      flask_app/app.py

      from flask import Flask
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def hello():
          return '<h1>Hello, World!</h1>'
      
      
      @app.route('/about/')
      def about():
          return '<h3>This is a Flask web application.</h3>'
      

      Save and close the file.

      You added a new function called about(). This function is decorated with the @app.route() decorator that transforms it into a view function that handles requests for the http://127.0.0.1:5000/about endpoint.

      With the development server running, visit the following URL using your browser:

      http://127.0.0.1:5000/about
      

      You will see the text This is a Flask web application. rendered in an <h3> HTML heading.

      You can also use multiple routes for one view function. For example, you can serve the index page at both / and /index/. To do this, open your app.py file for editing:

      Edit the file by adding another decorator to the hello() view function:

      flask_app/app.py

      from flask import Flask
      
      app = Flask(__name__)
      
      @app.route('/')
      @app.route('/index/')
      def hello():
          return '<h1>Hello, World!</h1>'
      
      @app.route('/about/')
      def about():
          return '<h3>This is a Flask web application.</h3>'
      

      Save and close the file.

      After adding this new decorator, you can access the index page at both http://127.0.0.1:5000/ and http://127.0.0.1:5000/index.

      You now understand what routes are, how to use them to make view functions, and how to add new routes to your application. Next, you’ll use dynamic routes to allow users to control the application’s response.

      Step 5 — Dynamic Routes

      In this step, you’ll use dynamic routes to allow users to interact with the application. You’ll make a route that capitalizes words passed through the URL, and a route that adds two numbers together and displays the result.

      Normally, users don’t interact with a web application by manually editing the URL. Rather, the user interacts with elements on the page that lead to different URLs depending on the user’s input and action, but for the purposes of this tutorial, you will edit the URL to demonstrate how to make the application respond differently with different URLs.

      First, open your app.py file for editing:

      If you allow the user to submit something to your web application, such as a value in the URL as you are going to do in the following edit, you should always keep in mind that your app should not directly display untrusted data (data the user submits). To display user data safely, use the escape() function that comes with the markupsafe package, which was installed along with Flask.

      Edit app.py and add the following line to the top of the file, above the Flask import:

      flask_app/app.py

      from markupsafe import escape
      from flask import Flask
      
      # ...
      

      Then, add the following route to the end of the file:

      flask_app/app.py

      # ...
      
      @app.route('/capitalize/<word>/')
      def capitalize(word):
          return '<h1>{}</h1>'.format(escape(word.capitalize()))
      

      Save and close the file.

      This new route has a variable section <word>. This tells Flask to take the value from the URL and pass it to the view function. The URL variable <word> passes a keyword argument to the capitalize() view function. The argument has the same name as the URL variable (word in this case). With this you can access the word passed through the URL and respond with a capitalized version of it using the capitalize() method in Python.

      You use the escape() function you imported earlier to render the word string as text. This is important to avoid Cross Site Scripting (XSS) attacks. If the user submits malicious JavaScript instead of a word, escape() will it render as text and the browser will not run it, keeping your web application safe.

      To display the capitalized word inside an <h1> HTML heading, you use the format() Python method, for more on this method, see How To Use String Formatters in Python 3

      With the development server running, open your browser and visit the following URLs. You can replace the highlighted words with any word of your choice.

      http://127.0.0.1:5000/capitalize/hello
      http://127.0.0.1:5000/capitalize/flask
      http://127.0.0.1:5000/capitalize/python
      

      You can see the word in the URL capitalized in an <h1> tag on the page.

      You can also use multiple variables in a route. To demonstrate this, you will add a route that adds two positive integer numbers together and displays the result.

      Open your app.py file for editing:

      Add the following route to the end of the file:

      flask_app/app.py

      # ...
      
      @app.route('/add/<int:n1>/<int:n2>/')
      def add(n1, n2):
          return '<h1>{}</h1>'.format(n1 + n2)
      

      Save and close the file.

      In this route, you use a special converter int with the URL variable (/add/<int:n1>/<int:n2>/) which only accepts positive integers. By default, URL variables are assumed to be strings and are treated as such.

      With the development server running, open your browser and visit the following URL:

      http://127.0.0.1:5000/add/5/5/
      

      The result will be the sum of the two numbers (10 in this case).

      You now have an understanding of how to use dynamic routes to display different responses in a single route depending on the requested URL. Next, you’ll learn how to troubleshoot and debug your Flask application in case of an error.

      Step 6 — Debugging A Flask Application

      When developing a web application, you will frequently run into situations where the application displays an error instead of the behavior you expect. You may misspell a variable or forget to define or import a function. To make fixing these problems easier, Flask provides a debugger when running the application in development mode. In this step, you will learn how to fix errors in your application using the Flask debugger.

      To demonstrate how to handle errors, you will create a route that greets a user from a list of usernames.

      Open your app.py file for editing:

      Add the following route to the end of the file:

      flask_app/app.py

      # ...
      
      @app.route('/users/<int:user_id>/')
      def greet_user(user_id):
          users = ['Bob', 'Jane', 'Adam']
          return '<h2>Hi {}</h2>'.format(users[user_id])
      

      Save and close the file.

      In the route above, the greet_user() view function receives a user_id argument from the user_id URL variable. You use the int converter to accept positive integers. Inside the function, you have a Python list called users, which contains three strings representing usernames. The view function returns a string that is constructed depending on the provided user_id. If the user_id is 0, the response will be Hi Bob in an <h2> tag because Bob is the first item in the list (the value of users[0]).

      With the development server running, open your browser and visit the following URLs:

      http://127.0.0.1:5000/users/0
      http://127.0.0.1:5000/users/1
      http://127.0.0.1:5000/users/2
      

      You will receive the following responses:

      Output

      Hi Bob Hi Jane Hi Adam

      This works well so far, but it can go wrong when you request a greeting for a user who doesn’t exist. To demonstrate how the Flask debugger works, visit the following URL:

      http://127.0.0.1:5000/users/3
      

      You’ll see a page that looks like this:

      Flask Debugger

      At the top, the page gives you the name of the Python exception, which is IndexError, indicating that the list index (3 in this case) is out of the list’s range (which is only from 0 to 2 because the list has only three items). In the debugger, you can see the traceback that tells you the lines of code that raised this exception.

      The last two lines of the traceback usually give the source of the error. In your case the lines may be something like the following:

      File "/home/USER/flask_app/app.py", line 28, in greet_user
          return '<h2>Hi {}</h2>'.format(users[user_id])
      

      This tells you that the error originates from the greet_user() function inside the app.py file, specifically in the return line.

      Knowing the original line that raises the exception will help you determine what went wrong in your code, and decide what to do to fix it.

      In this case you can use a simple try...except clause to fix this error. If the requested URL has an index outside the list’s range, the user will receive a 404 Not Found error, which is an HTTP error that tells the user the page they are looking for does not exist.

      Open your app.py file for editing:

      To respond with an HTTP 404 error, you will need Flask’s abort() function, which can be used to make HTTP error responses. Change the second line in the file to also import this function:

      flask_app/app.py

      from markupsafe import escape
      from flask import Flask, abort
      

      Then edit the greet_user() view function to look as follows:

      flask_app/app.py

      # ...
      
      @app.route('/users/<int:user_id>/')
      def greet_user(user_id):
          users = ['Bob', 'Jane', 'Adam']
          try:
              return '<h2>Hi {}</h2>'.format(users[user_id])
          except IndexError:
              abort(404)
      

      You use try above to test the return expression for errors. If there was no error, meaning that user_id has a value that matches an index in the users list, the application will respond with the appropriate greeting. If the value of user_id is outside the list’s range, an IndexError exception will be raised, and you use except to catch the error and respond with an HTTP 404 error using the abort() Flask helper function.

      Now, with the development server running, visit the URL again:

      http://127.0.0.1:5000/users/3
      

      This time you’ll see a standard 404 error page informing the user that the page does not exist.

      By the end of this tutorial, your app.py file will look like this:

      flask_app/app.py

      from markupsafe import escape
      from flask import Flask, abort
      
      app = Flask(__name__)
      
      
      @app.route('/')
      @app.route('/index/')
      def hello():
          return '<h1>Hello, World!</h1>'
      
      
      @app.route('/about/')
      def about():
          return '<h3>This is a Flask web application.</h3>'
      
      @app.route('/capitalize/<word>/')
      def capitalize(word):
          return '<h1>{}</h1>'.format(escape(word.capitalize()))
      
      @app.route('/add/<int:n1>/<int:n2>/')
      def add(n1, n2):
          return '<h1>{}</h1>'.format(n1 + n2)
      
      @app.route('/users/<int:user_id>/')
      def greet_user(user_id):
          users = ['Bob', 'Jane', 'Adam']
          try:
              return '<h2>Hi {}</h2>'.format(users[user_id])
          except IndexError:
              abort(404)
      

      You now have a general idea of how to use the Flask debugger to troubleshoot your errors and help you determine the appropriate course of action to fix them.

      Conclusion

      You now have a general understanding of what Flask is, how to install it, and how to use it to write a web application, how to run the development server, and how to use routes and view functions to display different web pages that serve specific purposes. You’ve also learned how to use dynamic routes to allow users to interact with your web application via the URL, and how to use the debugger to troubleshoot errors.

      If you would like to read more about Flask, check out the Flask topic page.



      Source link