One place for hosting & domains

      3 Easy Ways to Optimize Images for Web

      Visual content can help make your site more engaging and enhance the user experience. However, poorly optimized images can wreak havoc on your website’s performance and even harm your Search Engine Optimization (SEO) rankings.

      Optimizing images for web can help you improve your page load times and cut down on file bloat. This task may sound a little tedious, but with the right tools, you can simplify the process and boost your site’s performance in no time.

      In this article, we’ll talk about the importance of image optimization and its impact on your website. Then, we’ll suggest three easy methods for optimizing photos. Let’s dive in!

      The Importance of Image Optimization

      Image optimization is the process of reducing image file sizes to minimize load times. It typically involves compressing images while preserving their quality.

      Search engines take several factors into consideration when ranking the quality of a website. This includes a site’s Core Web Vitals score.

      Core Web Vitals is a set of metrics that are used by Google to measure a site’s performance. One of the most important metrics is the Largest Contentful Paint (LCP):

      Core Web Vitals LCP report

      LCP measures the time it takes for the largest element on the page to load. This element is usually a hero image.

      Large image files can lead to a poor LCP score. They can also result in high bounce rates, which can have a negative impact on your conversions. Therefore, optimizing images is one of the most effective ways to improve your site’s performance and boost your SEO.


      Different Image File Types

      If you use images on your website, it’s important to familiarize yourself with the different file types and when to use them. There are three main types of image formats:

      • JPEG: This file type helps you reduce the image size while retaining decent image quality, and it’s best suited for simple designs and lower-quality images.
      • PNG: PNG images tend to have better quality than JPEGs, and should ideally be used for photographs that contain a lot of detail.
      • GIF: This format uses a low number of colors, so it’s ideal for plain graphics like logos and icons.

      There are other image formats you might use, including vector graphics. This type of image file can be resized without losing its quality. The downside is that vector graphics are not as widely supported as other image types.

      Get Content Delivered Straight to Your Inbox

      Subscribe to our blog and receive great content just like this delivered straight to your inbox.

      3 Easy Ways to Optimize Images for the Web

      Fortunately, image optimization doesn’t require technical knowledge. There are a number of tools and best practices that can help you resize, compress, and convert images to the optimal conditions for the web. Let’s take a close look at a few different methods.

      1. Resize and Crop Images with a Photo Editing Tool

      Original images may be much larger than needed for the web. One of the easiest steps you can take to optimize images is to resize or crop them. You can do this with photo editing software like Adobe Photoshop.

      For example, you might take a screenshot to show how something works, but only need to show a small part of the screen. You can crop out all of the unnecessary areas from the screenshot using the default photo editor on your Operating System (OS). This will help you reduce the file size of the image while enabling your audience to focus on what is important.

      If you use Windows, you can easily crop and resize images in Microsoft Photos. To get started, open your image in the Photos app, then click on the first icon in the top menu:

      edit image

      You can then use the drag handles to crop your image:

      cropping images for web

      If you want to resize the image, click on the three-dot icon in the main menu and select Resize:

      resize website image

      This will launch a window where you can select a different file size, or set your own custom dimensions:


      resize image

      If you click on Define custom dimensions, you can change the width and height of the image. You can also control its quality from the available slider. For instance, if you want to compress your image to reduce its size, you can set the quality to 50%:

      resize images

      You can then click on Save resized copy. We recommend that you choose a different name for the resized image to avoid overriding the original one.

      2. Use an Online Compression Tool

      Another way to resize photos is to use an online compression tool. This can help you to significantly reduce the image file size without any noticeable changes in quality.

      Some optimization tools enable you to compress images in bulk. This can help you save a lot of time.

      Let’s look at two powerful image compression tools that you can use.



      TinyPNG is a user-friendly web app that enables you to compress up to 20 images at a time. It is free to use and supports WebP, JPEG, and PNG file types.

      With TinyPNG, you can reduce file sizes while retaining image quality. The result is optimized images that take up less server space and load faster.

      To optimize an image with TinyPNG, simply upload your image files into the box at the top of the page and wait for the compression process to complete:


      You can then review the results and download your optimized images. For raw images, you can expect reductions in the range of 40%-70%. Image Optimization tool

      is another online image optimizer that you can use. Like TinyPNG, it’s free (with a premium option) and lets you compress images in bulk. However, it offers more compression options than TinyPNG: optimize images for web

      For example, you can choose from three optimization modes, including lossy and lossless. With lossy compression, you can make your image file significantly smaller by removing large amounts of data from your image.

      Meanwhile, lossless compression reduces your file size without removing any data from the image. Therefore, this method is ideal for high-quality images. gives you more control over how your images are compressed. You can choose to prioritize image quality over file size or vice versa.

      To optimize an image with, simply upload the images you want to compress, select an optimization method, and choose a download option. For instance, you can download each file individually, download multiple files together in a .zip file or to Dropbox, or share them straight to Facebook and Twitter:

      download optimized images via

      The free version of gives you a lot of options. The major downside is that you are limited to uploading 1MB files. PRO lifts this limitation and adds more settings.

      3. Install a WordPress Image Optimization Plugins

      If you have a WordPress site, there are several image optimization plugins that you can use. These are designed to help you compress WordPress images and make your site load faster.

      Additionally, these plugins enable you to optimize your image right from your WordPress dashboard. Some of them will automatically compress any images that you upload to your site.

      Let’s look at some popular image optimization plugins for WordPress sites.


      Smush plugin for image optimization

      Smush is a popular WordPress image optimizer with over a million active installations and a five-star rating. It helps you improve your page load times by compressing and resizing your images.

      For example, the Bulk Smush feature detects images on your site that can be optimized and enables you to compress them in bulk:

      Bulk Smush optimize images for web

      You can also activate lazy loading to make your web pages load even faster:

      lazy load images

      Typically, your media files are loaded all at once, resulting in slower page speeds. With lazy loading, your images will load as users scroll down this page. This can make your content load faster.

      If you upgrade to Smush Pro, you’ll get access to more features, including the option to automatically serve images in Next-Gen WebP format. Plans start at $7.50 per month.

      ShortPixel Image Optimizer


      ShortPixel automatically shrinks image file sizes to help boost your site’s performance. However, it converts PNG images to JPEGs. While this can help you achieve faster load times, it may also reduce the quality of your content.

      With ShortPixel, you can choose from different compressions methods, including lossy and lossless:

      ShortPixel image compression settings

      You can also compress your thumbnails and create a backup of your original images. For more options, you can upgrade to the premium version, which starts at $3.99 per month.


      Jetpack for WordPress

      While Jetpack isn’t an image optimization plugin, its Site Accelerator feature includes an option for optimizing images and hosting them on a Content Delivery Network (CDN). A CDN is a network of servers designed to serve content from the device that’s closest to the user’s geographic location, thus improving page load times.

      You can find these image optimization options under the plugin’s Performance & speed settings:

      Enable Site Accelerator settings in Jetpack

      These features are available for free with Jetpack Boost. The plugin comes with other tools that help you enhance your site’s performance.

      Speed Up Your Site with Optimized Images

      Poorly optimized images can have a negative impact on your site’s performance. Fortunately,  you can speed up your site and improve SEO rankings simply by resizing and compressing your images.

      To recap, here are three easy ways to optimize images for the web:

      1. Resize and crop images using a program like Adobe Photoshop or Microsoft Photos.
      2. Use an online compression tool like TinyPNG or
      3. Install a WordPress optimization plugin like Smush Pro, Short Pixel, or Jetpack Boost.

      You can also improve the performance of your site by choosing a powerful hosting plan. Our DreamPress managed WordPress hosting offers a fast and reliable service with 24/7 support. Check out our plans today!

      You Dream It, We Code It

      Tap into 20+ years of coding expertise when you opt for our Web Development service. Just let us know what you want for your site — we take it from there.

      woman of color on laptop

      Source link

      How To Install Matomo Web Analytics on Ubuntu 20.04


      Matomo is an open-source, self-hosted web analytics application written in PHP.

      In this tutorial you will install Matomo and a MariaDB database using Docker Compose, then install Nginx to act as a reverse proxy for the Matomo app. Finally, you will enable secure HTTPS connections by using Certbot to download and configure SSL certificates from the Let’s Encrypt Certificate Authority.


      In order to complete this tutorial, you’ll first need the following:

      Note: These prerequisite steps can be skipped if you’re using DigitalOcean’s One-Click Docker Image. This image will have Docker, Docker Compose, and UFW already installed and configured.

      Launch a new Docker image in the region of your choice, then log in as the root user and proceed with the tutorial. Because you’ll be using the root user, you could leave off the sudo parts of all the commands that follow, but it’s not necessary.

      Finally, to enable SSL you’ll need a domain name pointed at your server’s public IP address. This should be something like or, for instance. If you’re using DigitalOcean, please see our DNS Quickstart for information on creating domain resources in our control panel.

      When you’ve satisfied all the prerequisites, proceed to Step 1, where you’ll download and launch the Matomo software.

      Step 1 — Running Matomo and MariaDB with Docker Compose

      Your first step will be to create the Docker Compose configuration that will launch containers for both the Matomo app and a MariaDB database.

      This tutorial will put your configuration inside a matomo directory in your home directory. You could also choose to work in an /opt/matomo directory or some other directory of your choosing.

      First ensure you’re in your home directory:

      Then create the matomo directory and cd into it:

      Now open a new blank YAML file called docker-compose.yml:

      This is the configuration file that the docker-compose software will read when bringing up your containers. Paste the following into the file:


      version: "3"
          image: mariadb
          command: --max-allowed-packet=64MB
          restart: always
            - MARIADB_DATABASE=matomo
            - MARIADB_USER
            - MARIADB_PASSWORD
            - ./db:/var/lib/mysql
          image: matomo
          restart: always
            - ./matomo:/var/www/html

      The file defines two services, one db service which is the MariaDB container, and an app service which runs the Matomo software. Both services also reference a named volume where they store some data, and the app service also opens up port 8080 on the loopback ( interface, which we’ll connect to via localhost.

      Save the file and exit your text editor to continue. In nano, press CTRL+O then ENTER to save, then CTRL+X to exit.

      The MariaDB container needs some configuration to be passed to it through environment variables in order to function. The docker-compose.yml file lists these environment variables, but not all of them have associated values. That’s because it’s good practice to keep passwords out of your docker-compose.yml file, especially if you’ll be committing it to a Git repository or other source control system.

      Instead, we’ll put the necessary information in a .env file in the same directory, which the docker-compose command will automatically load when we start our containers.

      Open a new .env file with nano:

      You’ll need to fill in a user name and password, as well as a strong password for the MariaDB root superuser account:



      One way of generating a strong password is to use the openssl command, which should be available on most any operating system. The following command will print out a random 30 character hash that you can use as a password:

      • openssl rand 30 | base64 -w 0 ; echo

      When you’re done filling out the information in your .env file, save it and exit your text editor.

      You’re now ready to bring up the two containers with docker-compose:

      • sudo docker-compose up -d

      The up subcommand tells docker-compose to start the containers (and volumes and networks) defined in the docker-compose.yml file, and the -d flag tells it to do so in the background (“daemonize”) so the command doesn’t take over your terminal. docker-compose will print some brief output as it starts the containers:


      Creating matomo_db_1 ... done Creating matomo_app_1 ... done

      When that’s done, Matomo should be running. You can test that a webserver is running at localhost:8080 by fetching the homepage using the curl command:

      • curl --head http://localhost:8080

      This will print out only the HTTP headers from the response:


      HTTP/1.1 200 OK Date: Tue, 25 Jan 2022 19:56:16 GMT Server: Apache/2.4.51 (Debian) X-Powered-By: PHP/8.0.14 X-Matomo-Request-Id: 1e953 Cache-Control: no-store, must-revalidate Referrer-Policy: same-origin Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' 'unsafe-inline' 'unsafe-eval' data:; Set-Cookie: MATOMO_SESSID=dde7d477b0822e166ed90448964ec1e7; path=/; HttpOnly; SameSite=Lax Content-Type: text/html; charset=utf-8

      The 200 OK response means the Matomo server is up and running, but it’s only available on localhost. The highlighted X-Matomo-Request-Id header indicates that the server is Matomo and not something else that might be configured to listen on port 8080. Next we’ll set up Nginx to proxy public traffic to the Matomo container.

      Step 2 — Installing and Configuring Nginx

      Putting a web server such as Nginx in front of your Matomo server can improve performance by offloading caching, compression, and static file serving to a more efficient process. We’re going to install Nginx and configure it to reverse proxy requests to Matomo, meaning it will take care of handing requests from your users to Matomo and back again. Using a non-containerized Nginx will also make it easier to add Let’s Encrypt SSL certificates in the next step.

      First, refresh your package list, then install Nginx using apt:

      • sudo apt update
      • sudo apt install nginx

      Allow public traffic to ports 80 and 443 (HTTP and HTTPS) using the “Nginx Full” UFW application profile:

      • sudo ufw allow "Nginx Full"


      Rule added Rule added (v6)

      Next, open up a new Nginx configuration file in the /etc/nginx/sites-available directory. We’ll call ours matomo.conf but you could use a different name:

      • sudo nano /etc/nginx/sites-available/matomo.conf

      Paste the following into the new configuration file, being sure to replace your_domain_here with the domain that you’ve configured to point to your Matomo server. This should be something like, for instance:


      server {
          listen       80;
          listen       [::]:80;
          server_name  your_domain_here;
          access_log  /var/log/nginx/matomo.access.log;
          error_log   /var/log/nginx/matomo.error.log;
          location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Proto https;
            proxy_pass http://localhost:8080;

      This configuration is HTTP-only for now, as we’ll let Certbot take care of configuring SSL in the next step. The rest of the config sets up logging locations and then passes all traffic, as well as some important proxy headers, along to http://localhost:8080, the Matomo container we started up in the previous step.

      Save and close the file, then enable the configuration by linking it into /etc/nginx/sites-enabled/:

      • sudo ln -s /etc/nginx/sites-available/matomo.conf /etc/nginx/sites-enabled/

      Use nginx -t to verify that the configuration file syntax is correct:


      nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

      And finally, reload the nginx service to pick up the new configuration:

      • sudo systemctl reload nginx

      Your Matomo site should now be available on plain HTTP. Load http://your_domain_here (you may have to click through a security warning) and it will look like this:

      Screenshot of the first page of the Matomo web installation process, with a

      Now that you have your site up and running over HTTP, it’s time to secure the connection with Certbot and Let’s Encrypt certificates. You should do this before going through Matomo’s web-based setup procedure.

      Step 3 — Installing Certbot and Setting Up SSL Certificates

      Thanks to Certbot and the Let’s Encrypt free certificate authority, adding SSL encryption to our Matomo app will take only two commands.

      First, install Certbot and its Nginx plugin:

      • sudo apt install certbot python3-certbot-nginx

      Next, run certbot in --nginx mode, and specify the same domain you used in the Nginx server_name config:

      • sudo certbot --nginx -d your_domain_here

      You’ll be prompted to agree to the Let’s Encrypt terms of service, and to enter an email address.

      Afterwards, you’ll be asked if you want to redirect all HTTP traffic to HTTPS. It’s up to you, but this is generally recommended and safe to do.

      After that, Let’s Encrypt will confirm your request and Certbot will download your certificate:


      Congratulations! You have successfully enabled You should test your configuration at: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/ Your key file has been saved at: /etc/letsencrypt/live/ Your cert will expire on 2021-12-06. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: Donating to EFF:

      Certbot will automatically reload Nginx to pick up the new configuration and certificates. Reload your site and it should switch you over to HTTPS automatically if you chose the redirect option.

      Your site is now secure and it’s safe to continue with the web-based setup steps.

      Step 4 — Setting Up Matomo

      Back in your web browser you should now have Matomo’s Welcome! page open via a secure https:// connection. Now you can enter usernames and passwords safely to complete the installation process.

      Click the Next button. You’ll be taken to the System Check step:

      Screenshot of Matomo's "System Check" page with a list of system properties with green checkmarks next to them

      This is a summary of the system Matomo is running on, and everything should be green checkmarks indicating there are no problems. Scroll all the way to the bottom and click the Next button.

      Now you’ll be on the Database Setup page:

      Screenshot of Matomo's "Database Setup" page, with a form for inputting database connection details

      The information you fill in on this page will tell the Matomo application how to connect to the MariaDB database. You’ll need the MARIADB_USER and MARIADB_PASSWORD that you chose in Step 1. You can copy them out of your .env file if you need to.

      Fill out the first four fields:

      • Database Server: db
      • Login: the username you set in the MARIADB_USER environment variable
      • Password: the password you set in the MARIADB_PASSWORD environment variable
      • Database Name: matomo

      The defaults are fine for the remaining two fields.

      Click Next once more. You’ll get a confirmation that the database was set up correctly. Click Next again. You’ll then need to set up an admin user, and finally you’ll set up information about the first website you want to collect analytics for.

      After all that, you should end up on step 8, a Congratulations page. You’re almost all done. Scroll down to the bottom and click the Continue to Matomo button, and you’ll be taken to the homepage:

      Screenshot of the Matomo homepage with a large orange

      There will be a large warning at the top of the page. There’s a small update you’ll need to do to Matomo’s configuration file to finish up this process.

      Back on the command line, open up the configuration file with a text editor:

      • sudo nano matomo/config/config.ini.php

      Near the top you should have a [General] section. Add the last three lines, highlighted below, to the end of that section:


      proxy_client_headers[] = "HTTP_X_FORWARDED_FOR"
      proxy_host_headers[] = "HTTP_X_FORWARDED_HOST"
      salt = "e0a81d6e54d6d2200efd0f0ef6ef8563"
      trusted_hosts[] = "localhost"
      trusted_hosts[] = ""
      trusted_hosts[] = "localhost:8080"
      assume_secure_protocol = 1
      force_ssl = 1

      These options let Matomo know that it’s safe to use port 8080, and that it should assume it’s always being accessed over a secure connection.

      Save and close the configuration file, then switch back to your browser and reload the page. The error should be gone, and you’ll be presented with a login prompt:

      Screenshot of Matomo's "Sign in" screen with a form for username and password

      Log in with the admin account you created during setup, and you should be taken to the dashboard:

      Screenshot of Matomo's homepage dashboard with a placeholder indicating "No data has been recorded yet" and instructions on how to set up the tracking code

      Because you’ve probably not set up your tracking code yet, the dashboard will indicate that no data has been recorded. Follow the instructions to finish setting up the JavaScript code on your website to start receiving analytics data.


      In this tutorial, you launched the Matamo analytics app and a MariaDB database using Docker Compose, then set up an Nginx reverse proxy and secured it using Let’s Encrypt SSL certificates.

      You’re now ready to set up your website and add the Matomo analytics tracking script. For more information about operating the Matomo software, please see the official Matomo documentation.

      Source link

      How To Use and Validate Web Forms with Flask-WTF

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


      Web forms, such as text fields and text areas, give users the ability to send data to your application, whether that’s a drop-down or a radio button that the application will use to perform an action, or to send large areas of text to be processed or displayed. For example, in a social media application, you might give users a box where they can add new content to their pages.

      Flask is a lightweight Python web framework that provides useful tools and features for creating web applications in the Python Language. To render and validate web forms in a safe and flexible way in Flask, you’ll use Flask-WTF, which is a Flask extension that helps you use the WTForms library in your Flask application.

      WTForms is a Python library that provides flexible web form rendering. You can use it to render text fields, text areas, password fields, radio buttons, and others. WTForms also provides powerful data validation using different validators, which validate that the data the user submits meets certain criteria you define. For example, if you have a required field, you can ensure data the user submits is provided, or has a certain length.

      WTForms also uses a CSRF token to provide protection from CSRF attacks, which are attacks that allows the attacker to execute unwanted actions on a web application in which the user is authenticated. A successful CSRF attack can force the user to perform state-changing requests like transferring funds to the attacker’s bank account in a banking application, changing the user’s email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.

      In this tutorial, you’ll build a small web application that demonstrates how to render and validate web forms using Flask-WTF. The application will have a page for displaying courses that are stored in a Python list, and the index page will have a form for entering the course title, its description, price, availability, and level (beginner, intermediate, or advanced).


      Step 1 — Installing Flask and Flask-WTF

      In this step, you’ll install Flask and Flask-WTF, which also installs the WTForms library automatically.

      With your virtual environment activated, use pip to install Flask and Flask-WTF:

      • pip install Flask Flask-WTF

      Once the installation is successfully finished, you’ll see a line similar to the following at the end of the output:


      Successfully installed Flask-2.0.2 Flask-WTF-1.0.0 Jinja2-3.0.3 MarkupSafe-2.0.1 WTForms-3.0.0 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1

      As you can see, the WTForms library was also installed as a dependency of the Flask-WTF package. The rest of the packages are Flask dependencies.

      Now that you’ve installed the required Python packages, you’ll set up a web form next.

      Step 2 — Setting up Forms

      In this step, you’ll set up a web form using fields and validators you’ll import from the WTForms library.

      You’ll set up the following fields:

      • Title: A text input field for the course title.
      • Description: A text area field for the course description.
      • Price: An integer field for the price of the course.
      • Level: A radio field for the course level with three choices: Beginner, Intermediate, and Advanced.
      • Available: A checkbox field that indicates whether the course is currently available.

      First, open a new file called in your flask_app directory. This file will have the forms you’ll need in your application:

      This file will have a class that represents your web form. Add the following imports at the top:


      from flask_wtf import FlaskForm
      from wtforms import (StringField, TextAreaField, IntegerField, BooleanField,
      from wtforms.validators import InputRequired, Length

      To build a web form, you will create a subclass of the FlaskForm base class, which you import from the flask_wtf package. You also need to specify the fields you use in your form, which you will import from the wtforms package.

      You import the following fields from the WTForms library:

      In the line from wtforms.validators import InputRequired, Length, you import validators to use on the fields to make sure the user submits valid data. InputRequired is a validator you’ll use to ensure the input is provided, and Length is for validating the length of a string to ensure it has a minimum number of characters, or that it doesn’t exceed a certain length.

      Next, add the following class after the import statements:


      class CourseForm(FlaskForm):
          title = StringField('Title', validators=[InputRequired(),
                                                   Length(min=10, max=100)])
          description = TextAreaField('Course Description',
          price = IntegerField('Price', validators=[InputRequired()])
          level = RadioField('Level',
                             choices=['Beginner', 'Intermediate', 'Advanced'],
          available = BooleanField('Available', default="checked")

      Save and close the file.

      In this CourseForm class, you inherit from the FlaskForm base class you imported earlier. You define a collection of form fields as class variables using the form fields you imported from the WTForms library. When you instantiate a field, the first argument is the field’s label.

      You define the validators for each field by passing a list of the validators you import from the wtforms.validators module. The title field, for example, has the string 'Title' as a label, and two validators:

      • InputRequired: To indicate that the field should not be empty.
      • Length: Takes two arguments; min is set to 10 to make sure that the title is at least 10 characters long, and max is set to 100 to ensure it doesn’t exceed 100 characters.

      The description text area field has an InputRequired validator and a Length validator with the max parameter set to 200, with no value for the min parameter, which means the only requirement is that it doesn’t exceed 200 characters.

      Similarly you define a required integer field for the price of the course called price.

      The level field is a radio field with multiple choices. You define the choices in a Python list and pass it to the choices parameter. You also define the field as required using the InputRequired validator.

      The available field is a check box field. You set a default 'checked' value by passing it to the default parameter. This means the check box will be checked when adding new courses unless the user unchecks it, meaning courses are available by default.

      For more on how to use the WTForms library, see the Crash Course page on the WTForms documentation. See the Fields page for more fields, and the Validators page for more validators to validate form data.

      You’ve configured your web form in a file. Next, you’ll create a Flask application, import this form, and display its fields on the index page. You’ll also display a list of courses on another page.

      Step 3 — Displaying the Web Form and Courses

      In this step, you’ll create a Flask application, display the web form you created in the previous step on the index page, and also create a list of courses and a page for displaying the courses on it.

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

      This file will import the necessary class and helpers from Flask, and the CourseForm from the file. You’ll build a list of courses, then instantiate the form and pass it to a template file. Add the following code to


      from flask import Flask, render_template, redirect, url_for
      from forms import CourseForm
      app = Flask(__name__)
      app.config['SECRET_KEY'] = " secret key'
      courses_list = [{
          'title': 'Python 101',
          'description': 'Learn Python basics',
          'price': 34,
          'available': True,
          'level': 'Beginner'
      @app.route('/', methods=('GET', 'POST'))
      def index():
          form = CourseForm()
          return render_template('index.html', form=form)

      Save and close the file.

      Here you import the following from Flask:

      • The Flask class to create a Flask application instance.
      • The render_template() function to render the index template.
      • The redirect() function to redirect the user to the courses page once a new course is added.
      • The url_for() function for building URLs.

      First you import the CourseForm() class from the file, then you create a Flask application instance called app.

      You set up a secret key configuration for WTForms to use when generating a CSRF token to secure your web forms. The secret key should be a long random string. See Step 3 of How To Use Web Forms in a Flask Application for more information on how to obtain a secret key.

      Then you create a list of dictionaries called courses_list, which currently has one dictionary with a sample course titled 'Python 101'. Here, you use a Python list as a data store for demonstration purposes. In a real world scenario, you’ll use a database such as SQLite. See How To Use an SQLite Database in a Flask Application to learn how to use a database to store your courses’ data.

      You create a / main route using the app.route() decorator on the index() view function. It accepts both GET and POST HTTP methods in the methods parameter. GET methods are for retrieving data, and POST requests are for sending data to the server, through a web form for example. For more, see How To Use Web Forms in a Flask Application.

      You instantiate the CourseForm() class that represents the web form and save the instance in a variable called form. You then return a call to the render_template() function, passing it a template file called index.html and the form instance.

      To display the web form on the index page, you will first create a base template, which will have all the basic HTML code other templates will also use to avoid code repetition. Then you’ll create the index.html template file you rendered in your index() function. To learn more about templates, see How to Use Templates in a Flask Application.

      Create a templates folder in your flask_app directory where Flask searches for templates, then open a template file called base.html, which will be the base template for other templates:

      • mkdir templates
      • nano templates/base.html

      Add the following code inside the base.html file to create the base template with a navbar and a content block:


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

      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.

      Save and close the file.

      Next, open a template called index.html. This is the template you referenced in the file:

      • nano templates/index.html

      This file will have the web form you passed to the index.html template via the form variable. Add the following code to it:


      {% extends 'base.html' %}
      {% block content %}
          <h1>{% block title %} Add a New Course {% endblock %}</h1>
          <form method="POST" action="/">
              {{ form.csrf_token }}
                  {{ form.title.label }}
                  {{ form.title(size=20) }}
              {% if form.title.errors %}
                  <ul class="errors">
                      {% for error in form.title.errors %}
                          <li>{{ error }}</li>
                      {% endfor %}
              {% endif %}
                  {{ form.description.label }}
              {{ form.description(rows=10, cols=50) }}
              {% if form.description.errors %}
                  <ul class="errors">
                      {% for error in form.description.errors %}
                          <li>{{ error }}</li>
                      {% endfor %}
              {% endif %}
                  {{ form.price.label }}
                  {{ form.price() }}
              {% if form.price.errors %}
                  <ul class="errors">
                      {% for error in form.price.errors %}
                          <li>{{ error }}</li>
                      {% endfor %}
              {% endif %}
                  {{ form.available() }} {{ form.available.label }}
              {% if form.available.errors %}
                  <ul class="errors">
                      {% for error in form.available.errors %}
                          <li>{{ error }}</li>
                      {% endfor %}
              {% endif %}
                  {{ form.level.label }}
                  {{ form.level() }}
              {% if form.level.errors %}
                  <ul class="errors">
                      {% for error in form.level.errors %}
                          <li>{{ error }}</li>
                      {% endfor %}
              {% endif %}
                  <input type="submit" value="Add">
      {% endblock %}

      Save and close the file.

      You extend the base template, and set a title in an <h1> tag. Then you render the web form fields inside a <form> tag, setting its method to POST and the action to the / main route, which is the index page. You first render the CSRF token WTForms uses to protect your form from CSRF attacks using the line {{ form.csrf_token }}. This token gets sent to the server with the rest of the form data. Remember to always render this token to secure your forms.

      You render each field using the syntax form.field() and you render its label using the syntax form.field.label. You can pass arguments to the field to control how it is displayed. For example, you set the size of the title input field in {{ form.title(size=20) }}, and you set the numbers of rows and columns for the description text area via the parameters rows and cols the same way you would do normally in HTML. You can use the same method to pass additional HTML attributes to a field such as the class attribute to set a CSS class.

      You check for validation errors using the syntax if form.field.errors. If a field has errors, you loop through them with a for loop and display them in a list below the field.

      While in your flask_app directory with your virtual environment activated, tell Flask about the application ( in this case) using the FLASK_APP environment variable. Then set the FLASK_ENV environment variable to development to run the application in development mode and get access to the debugger. For more information about the Flask debugger, see How To Handle Errors in a Flask Application. Use the following commands to do this (on Windows, use set instead of export):

      • export FLASK_APP=app
      • export FLASK_ENV=development

      Next, run the application:

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

      You’ll see the web form displayed on the index page:

      Index Page

      Try to submit the form without filling in the title. You’ll see an error message informing you that the title is required. Experiment with the form by submitting invalid data (such as a short title less than 10 characters long, or a description over 200 characters long) to see other error messages.

      Filling the form with valid data does nothing so far because you don’t have code that handles form submission. You’ll add the code for that later.

      For now, you need a page to display the courses you have in your list. Later, handling the web form data will add a new course to the list and redirect the user to the courses page to see the new course added to it.

      Leave the development server running and open another terminal window.

      Next, open to add the courses route:

      Add the following route at the end of the file:


      # ...
      def courses():
          return render_template('courses.html', courses_list=courses_list)

      Save and close the file.

      This route renders a template called courses.html, passing it the courses_list list.

      Then create the courses.html template to display courses:

      • nano templates/courses.html

      Add the following code to it:


      {% extends 'base.html' %}
      {% block content %}
          <h1>{% block title %} Courses {% endblock %}</h1>
          {% for course in courses_list %}
              <h2> {{ course['title'] }} </h2>
              <h4> {{ course['description'] }} </h4>
              <p> {{ course['price'] }}$ </p>
              <p><i>({{ course['level'] }})</i></p>
                  {% if course['available'] %}
                  {% else %}
                      Not Available
                  {% endif %}</p>
          {% endfor %}
      {% endblock %}

      Save and close the file.

      You set a title and loop through the items of the courses_list list. You display the title in an <h2> tag, the description in an <h4> tag, and the price and course level in a <p> tag.
      You check whether the course is available using the condition if course['available']. You display the text “Available” if the course is available, and the text “Not Available” if it’s not available.

      Use your browser to go to the courses page:

      You’ll see a page with one course displayed, because you only have one course in your course list so far:

      Courses Page

      Next, open base.html to add a link to the courses page in the navigation bar:

      Edit it to look as follows:


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

      Save and close the file.

      Refresh the index page, and you’ll see a new Courses link in the navigation bar.

      You’ve created the pages you need for your application: An index page with a web form for adding new courses and a page for displaying the courses you have in your list.

      To make the application functional, you need to handle the web form data when the user submits it by validating it and adding it to the courses list. You’ll do this next.

      Step 4 — Accessing Form Data

      In this step, you’ll access data the user submits, validate it, and add it to the list of courses.

      Open to add code for handling the web form data inside the index() function:

      Edit the index() function to look as follows:


      # ...
      @app.route('/', methods=('GET', 'POST'))
      def index():
          form = CourseForm()
          if form.validate_on_submit():
              return redirect(url_for('courses'))
          return render_template('index.html', form=form)

      Save and close the file.
      Here, you call the validate_on_submit() method on the form object, which checks that the request is a POST request, and runs the validators you configured for each field. If at least one validator returns an error, the condition will be False, and each error will be displayed below the field that caused it.

      If the submitted form data is valid, the condition is True, and the code below the if statement will be executed. You build a course dictionary, and use the append method to add the new course to the courses_list list. You access the value of each field using the syntax After you add the new course dictionary to the courses list, you redirect the user to the Courses page.

      With the development server running, visit the index page:

      Fill the form with valid data and submit it. You’ll be redirected to the Courses page, and you’ll see the new course displayed on it.


      You made a Flask application that has a web form you built using the Flask-WTF extension and the WTForms library. The form has several types of fields to receive data from the user, validate it using special WTForms validators, and add it to a data store.

      If you would like to read more about Flask, check out the other tutorials in the How To Create Web Sites with Flask series.

      Source link