Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Mastering Flask Web and API Development
Mastering Flask Web and API Development

Mastering Flask Web and API Development: Build and deploy production-ready Flask apps seamlessly across web, APIs, and mobile platforms

Arrow left icon
Profile Icon Sherwin John C. Tragura
Arrow right icon
€29.99
Paperback Aug 2024 494 pages 1st Edition
eBook
€15.99 €23.99
Paperback
€29.99
Subscription
Free Trial
Renews at €18.99p/m
Arrow left icon
Profile Icon Sherwin John C. Tragura
Arrow right icon
€29.99
Paperback Aug 2024 494 pages 1st Edition
eBook
€15.99 €23.99
Paperback
€29.99
Subscription
Free Trial
Renews at €18.99p/m
eBook
€15.99 €23.99
Paperback
€29.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Table of content icon View table of contents Preview book icon Preview Book

Mastering Flask Web and API Development

A Deep Dive into the Flask Framework

Flask is a Python web framework that was created by Armin Ronacher to solve both web-based and API-related requirements that need a rapid development approach. It is a lightweight framework with helper classes and methods, a built-in server, a debugger, and a reloader, all of which are required for building scalable web applications and web services.

Unlike the Django framework, Flask is minimalistic and slimmer in that it requires more experience in using Python to craft various coding techniques and workarounds to implement its components. It is more open-ended and extensible than the full-stack Django, which is more friendly to newbies because of its easy-to-build projects and reusable components.

This first chapter will showcase the essential task itineraries that cover the initial components and base features of Flask 3.x that are essential in initiating our web development.

In this chapter, we will cover the following development tasks:

  • Setting up the project baseline
  • Creating routes and navigations
  • Managing the requests and response data
  • Implementing view templates
  • Creating web forms
  • Building the data layer with PostgreSQL
  • Managing the project structure

Technical requirements

The first chapter will focus on building a prototype for an Online Personal Counseling System that simulates a face-to-face consultation between a patient and a counselor while highlighting the base components of Flask 3.x. The application will cover modules such as managing users, questionnaires, and some reports. The code for this chapter can be found at https://github.com/PacktPublishing/Mastering-Flask-Web-Development/tree/main/ch01.

Setting up the project baseline

Gathering and studying the system requirements for the development environment for the proposed project is essential. Some of these requirements include the correct versions of the installers and libraries, the appropriate servers, and the inclusion of other essential dependencies. We have to perform various setups before kicking off our projects.

Installing the latest Python version

All our applications will run on the Python 11 environment for faster performance. The updated Python installer for all operating systems is available at https://www.python.org/downloads/.

Installing the Visual Studio (VS) Code editor

The Django framework has a django-admin command that generates a project structure, but Flask does not have that. We can use a terminal console or a tool such as the Visual Studio (VS) Code editor that can help developers create a Flask project. The VS Code installer is available at https://code.visualstudio.com/download.

After installing the VS Code editor, we can create a filesystem folder through it and start a Flask project. To create the folder, we should go to the Open Folder option under File or use the Ctrl + K + O shortcut to open the Open Folder mini-window. Figure 1.1 shows a sample process of creating a Flask project using the editor:

Figure 1.1 – Creating a Flask project folder using the VS Code editor

Figure 1.1 – Creating a Flask project folder using the VS Code editor

Creating the virtual environment

Another aspect of developing a Flask project is having a repository called a virtual environment that can hold its libraries. It is a mechanism or a tool that can manage all dependencies of a project by isolating these dependencies from the global repository and other project dependencies. The following are the advantages of using this tool in developing Flask-based applications:

  • It can avoid broken module versions and collisions with other existing similar global repository libraries.
  • It can help build a dependency tree for the project.
  • It can help ease the deployment of applications with libraries to both physical and cloud-based servers.

A Python extension named virtualenv is required to set up these virtual environments. To install the extension, run the following command in the terminal:

pip install virtualenv

After this installation, we need to run python virtualenv -m ch01-01 to create our first virtual environment for our Flask project. Figure 1.2 shows a snapshot of creating our ch01-env repository:

Figure 1.2 – Creating a virtual environment

Figure 1.2 – Creating a virtual environment

The next step is to open the project and link it to the virtual environment created for it. Pressing Ctrl + Shift + P in VS Code will open the Command Palette area. Here, we can search for Python: Select Interpreter. Clicking this option will lead you to the Enter interpreter path… menu command and eventually to the Find… option. This Find… option will help you locate the virtual environment’s Python.exe file in the /Scripts folder. Figure 1.3 shows a snapshot of locating the Python interpreter in the repository’s /Scripts folder:

Figure 1.3 – Locating the Python interpreter of the virtual environment

Figure 1.3 – Locating the Python interpreter of the virtual environment

Afterward, the virtual environment must be activated for the project to utilize it. You must run /Scripts/activate.bat in Windows or /bin/activate in Linux through the editor’s internal console. Upon activation, the terminal should show the name of the virtual environment in its prompt (for example, (ch01-env) C:\).

Installing the Flask 3.x libraries

The integrated terminal of VS Code will appear after right-clicking the explorer portion of the editor, which leads to the Open in Integrated Terminal option. Once it appears on the lower right-hand side, activate the virtual environment first, then install all Flask dependencies into the repository by running pip install flask.

Once all the requirements are in place, we are ready to create our baseline application.

Creating the Flask project

The first component that must be implemented in the main project folder (that is, ch01) is the application file, which can be main.py or sometimes app.py. This component will become the top-level module the Flask will recognize when the server starts. Here is the baseline application file for our Online Personal Counseling System prototype:

from flask import Flask
app = Flask(__name__)
@app.route('/', methods = ['GET'])
def index():
    return "This is an online … counseling system (OPCS)"
if __name__ == '__main__':
    app.run(debug=True)

Let’s dissect and scrutinize the essential parts of the given main.py file:

  • An imported Flask class from the flask package plays a considerable role in building the application. This class provides all the utilities that implement the Werkzeug specifications, which include features such as managing the requests and the responses of every route, redirecting pages, handling form data, accessing and creating cookies, parsing custom and built-in headers, and even providing debuggers for the development environment. In other words, the Flask instance is the main element in building a Web Server Gateway Interface (WSGI)-compliant application.

Werkzeug

Werkzeug is a WSGI-based library or module that provides Flask with the necessary utilities, including a built-in server, for running WSGI-based applications.

  • The imported Flask instance must be instantiated once per application. The __name__ argument must be passed to its constructor to provide Flask with a reference to the main module without explicitly setting its actual package. Its purpose is to provide Flask with the reach it needs in providing the utilities across the application and to register the components of the project to the framework.
  • The if statement tells the Python interpreter to run Werkzeug’s built-in development server if the module is main.py. This line validates the main.py module as the top-level module of the project.
  • app.run() calls and starts the built-in development server of Werkzeug. Setting its debug parameter to True sets development or debug mode and enables Werkzeug’s debugger tool and automatic reloading. Another way is to create a configuration file that will set FLASK_DEBUG to True. We can also set development mode by running main.py using the flask run command with the --debug option. Other configuration approaches before Flask 3.0, such as using FLASK_ENV, are already deprecated.

Running the python main.py command on the VS Code terminal will start the built-in development server and run our application. A server log will be displayed on the console with details that include the development mode, the debugger ID, and the URL address. The default port is 5000, while the host is localhost.

Now, it is time to explore the view functions of our Flask application. These are the components that manage the incoming requests and outgoing responses.

Creating routes and navigations

Routing is a mapping of URL pattern(s) and other related details to a view function that’s done using Flask’s route decorators. On the other hand, the view function is a transaction that processes an incoming request from the clients and, at the same time, returns the necessary response to them. It follows a life cycle and returns an HTTP status as part of its response.

There are different approaches to assigning URL patterns to view functions. These include creating static and dynamic URL patterns, mapping URLs externally, and mapping multiple URLs to a view function.

Creating static URLs

Flask has several built-in route decorators that implement some of its components, and @route decorator is one of these. @route directly maps the URL address to the view function seamlessly. For instance, @route maps the index() view function presented in the project’s main.py file to the root URL or /, which makes index() the view function of the root URL.

But @route can map any valid URL pattern to any view function. A URL pattern is accepted if it follows the following best practices:

  • All characters must be in lowercase.
  • Use only forward slashes to establish site hierarchy.
  • URL names must be concise, clear, and within the business context.
  • Avoid spaces and special symbols and characters as much as possible.

The following home() view function renders an introductory page of our ch01 application and uses the URL pattern of /home for its access:

@app.route('/home')
def home():
    return '''
       <html><head><title>Online Personal … System</title>
          </head><body>
           <h1>Online … Counseling System (OPCS)</h1>
           <p>This is a template of a web-based counseling
              application where counselors can … … …</em>
           </body></html>
       '''

Now, Flask accepts simple URLs such as /home or complex ones with slashes and path-like hierarchy, including these multiple URLs.

Assigning multiple URLs

A view function can have a stack of @route decorators annotated on it. Flask allows us to map these valid multiple URLs if there is no conflict with other view functions and within that stack of @route mappings. The following version of the home() view function now has three URLs, which means any of these addresses can render the home page:

@app.route('/home')
@app.route('/information')
@app.route('/introduction')
def home():
    return '''<html><head>
             <title>Online Personal … System</title>
        </head><body>
           <h1>Online … Counseling System (OPCS)</h1>
            … … … … …
        </body></html>
       '''

Aside from complex URLs, Flask is also capable of creating dynamic routes.

Applying path variables

Adding path variables makes a URL dynamic and changeable depending on the variations of the values passed to it. Although some SEO experts may disagree with having dynamic URLs, the Flask framework can allow view functions with changeable URL patterns to be implemented.

In Flask, a path variable is declared inside a diamond operator (<>) and placed within the URL path. The following view function has a dynamic URL with several path variables:

@app.route('/exam/passers/list/<float:rate>/<uuid:docId>')
def report_exam_passers(rating:float, docId:uuid4 = None):
    exams = list_passing_scores(rating)
    response = make_response(
      render_template('exam/list_exam_passers.html',
           exams=exams, docId=docId), 200)
    return response

As we can see, path variables are identified with data types inside the diamond operator (<>) using the <type:variable> pattern. These parameters are set to None if the path variables are optional. The path variable is considered a string type by default if it has no associated type hint. Flask 3.x offers these built-in data types for path variables:

  • string: Allows all valid characters except for slashes.
  • int: Takes integer values.
  • float: Accepts real numbers.
  • uuid: Takes unique 32 hexadecimal digits that are used to identify or represent records, documents, hardware gadgets, software licenses, and other information.
  • path: Fetches characters, including slashes.

These path variables can’t function without the corresponding parameters of the same name and type declared in the view function’s parameter list. In the previous report_exam_passers() view function, the local rating and docId parameters are the variables that will hold the values of the path variables, respectively.

But there are particular or rare cases where path variables should be of a type different than the supported ones. View functions with path variables declared as list, set, date, or time will throw Status Code 500 in Flask. As a workaround, the Werkzeug bundle of libraries offers a BaseConverter utility class that can help customize a variable type for paths that allows other types to be part of the type hints. The following view function requires a date type hint to generate a certificate in HTML format:

@app.route('/certificate/accomp/<string:name>/  <string:course>/<date:accomplished_date>')
def show_certification(name:str, course:str, accomplished_date:date):
    certificate = """<html><head>
          <title>Certificate of Accomplishment</title>
         </head><body>
           <h1>Certificate of Accomplishment</h1>
           <p>The participant {} is, hereby awarded this certificate of accomplishment, in {} course on {} date for passing all exams. He/she proved to be ready for any of his/her future endeavors.</em>
         </body></html>
    """.format(name, course, accomplished_date)
    return certificate, 200

accomplished_date in show_certification() is a date hint type and will not be valid until the following tasks are implemented:

  • First, subclass BaseConverter from the werkzeug.routing module. In the /converter package of this project, there is a module called date_converter.py that implements our date hint type, as shown in the following code:
    from werkzeug.routing import BaseConverter
    from datetime import datetime
    class DateConverter(BaseConverter):
       def to_python(self, value):
         date_value = datetime.strptime(value, "%Y-%m-%d")
         return date_value

    The given DateConverter will custom-handle date variables within our Flask application.

  • BaseConverter has a to_python() method that must be overridden to implement the necessary conversion process. In the case of DateConverter, we need strptime() so that we can convert the path variable value in the yyyy-mm-dd format into the datetime type.
  • Lastly, declare our new custom converter in the Flask instance of the main.py module. The following snippet registers DateConverter to app:
    app = Flask(__name__)
    app.url_map.converters['date'] = DateConverter

After following all these steps, the custom path variable type – for instance, date – can now be utilized across the application.

Assigning URLs externally

There is also a way to implement a routing mechanism without using the @route decorator, and that’s by utilizing Flask’s add_url_rule() method to register views. This approach binds a valid request handler to a unique URL pattern for every call to add_url_rule() of the app instance in the main.py module, not in the handler’s module scripts, thus making this approach an external way of building routes. The following arguments are needed by the add_url_rule() method to perform mapping:

  • The URL pattern with or without the path variables.
  • The URL name and, usually, the exact name of the view function.
  • The view function itself.

The invocation of this method must be in the main.py file, anywhere after its @route implementations and view imports. The following main.py snippet shows the external route mapping of the show_honor_dismissal() view function to its dynamic URL pattern. This view function generates a termination letter for the counseling and consultation agreement between a clinic and a patient:

app = Flask(__name__)
def show_honor_dissmisal(counselor:str, effective_date:date, patient:str):
    letter = """
       … … … … …
       </head><body>
           <h1> Termination of Consultation </h1>
           <p>From: {}
           <p>Head, Counselor
           <p>Date: {}
           <p>To: {}
           <p>Subject: Termination of consultation
                    <p>Dear {},
                    … … … … … …
                    <p>Yours Sincerely,
                    <p>{}
                </body>
            </html>
    """.format(counselor, effective_date, patient, patient, counselor)
    return letter, 200
app.add_url_rule('/certificate/terminate/<string:counselor>/<date:effective_date>/<string:patient>', 'show_honor_dissmisal', views.certificates.show_honor_dissmisal)

Binding URL mappings to views using add_url_rule() is not only confined to the decorated function views but is also necessary for class-based views.

Implementing class-based views

Another way to create the view layer is through Flask’s class-based view approach. Unlike the Django framework, which uses mixin programming to implement its class-based views, Flask provides two API classes, namely View and MethodView, that can directly subclass any custom view implementations.

The most common and generic class to implement HTTP GET operations is the View class from the flask.views module. It has a dispatch_request() method that executes the request-response transactions like a typical view function. Thus, subclasses must override this core method to implement their view transactions. The following class, ListUnpaidContractView, renders a list of patients with payments due to the clinic:

from flask.views import View
class ListUnpaidContractView(View):
    def dispatch_request(self):
        contracts = select_all_unpaid_patient()
        return render_template("contract/ list_patient_contract.html", contracts=contracts)

select_all_unpaid_patient() will provide the patient records from the database. All these records will be rendered to the list_patient_contract.html template. Now, aside from overriding the dispatch_request() method, ListUnpaidContractView also inherits all the attributes and helper methods from the View class, including the as_view() static method, which creates a view name for the view. During view registration, this view name will serve as the view_func name of the custom View class in the add_url_rule() method with its mapped URL pattern. The following main.py snippet shows how to register ListUnpaidContractView:

app.add_url_rule('/contract/unpaid/patients', view_func=ListUnpaidContractView.as_view('list-unpaid-view'))

If a View subclass needs an HTTP POST transaction, it has a built-class class attribute called methods that accepts a list of HTTP methods the class needs to support. Without it, the default is the [ "GET" ] value. Here is another custom View class of our Online Personal Counselling System app that deletes existing patient contracts of the clinic:

class DeleteContractByPIDView(View):
    methods = ['GET', 'POST']
    … … … … … …
    def dispatch_request(self):
       if request.method == "GET":
          pids = list_pid()
          return render_template("contract/ delete_patient_contract.html", pids=pids)
       else:
          pid = int(request.form['pid'])
          result = delete_patient_contract_pid(pid)
          if result == False:
               pids = list_pid()
               return render_template("contract/ delete_patient_contract.html", pids=pids)
          contracts = select_all_patient_contract()
          return render_template("contract/ list_patient_contract.html", contracts=contracts)

DeleteContractByPIDView handles a typical form-handling transaction, which has both a GET operation for loading the form page and a POST operation to manage the submitted form data. The POST operation will verify if the patient ID submitted by the form page exists, and it will eventually delete the contract(s) of the patient using the patient ID and render an updated list of contracts.

Other than the View class, an alternative API that can also build view transactions is the MethodView class. This class is suitable for web forms since it has the built-in GET and POST hints or templates that subclasses need to define but without the need to identify the GET transactions from POST, like in a view function. Here is a view that uses MethodView to manage the contracts of the patients in the clinic:

from flask.views import MethodView
class ContractView(MethodView):
    … … … … … …
    def get(self):
        return render_template("contract/ add_patient_contract.html")
    def post(self):
        pid = request.form['pid']
        approver = request.form['approver']
        … … … … … …
        result = insert_patient_contract(pid=int(pid), approved_by=approver, approved_date=approved_date, hcp=hcp, payment_mode=payment_mode, amount_paid=float(amount_paid), amount_due=float(amount_due))
        if result == False:
          return render_template("contract/ add_patient_contract.html")
        contracts = select_all_patient_contract()
        return render_template("contract/ list_patient_contract.html", contracts=contracts)

The MethodView class does not have a methods class variable to indicate the HTTP methods supported by the view. Instead, the subclass can select the appropriate HTTP hints from MethodView, which will then implement the required HTTP transactions of the custom view class.

Since MethodView is a subclass of the View class, it also has an as_view() class method that creates a view_func name of the view. This is also necessary for add_url_rule() registration.

Aside from GET and POST, the MethodView class also provides the PUT, PATCH, and DELETE method hints for API-based applications. MethodView is better than the View API because it organizes the transactions according to HTTP methods and checks and executes these HTTP methods by itself at runtime. In general, between the decorated view function and the class-based ones, the latter approach provides a complete Flask view component because of the attributes and built-in methods inherited by the view implementation from these API classes. Although the decorated view function can support a flexible and open-ended strategy for scalable applications, it cannot provide an organized base functionality that can supply baseline view features to other related views, unlike in a class-based approach. However, the choice still depends on the scope and requirements of the application.

Now that we’ve created and registered the routes, let’s scrutinize these view implementations and identify the essential Flask components that compose them.

Managing request and response data

At this point, we already know that routing is a mechanism for mapping view functions to their URLs. But besides that, routing declares any valid functions to be view implementations that can manage the incoming request and outgoing response.

Retrieving the request object

Flask uses its request object to carry cookies, headers, parameters, form data, form objects, authorization data, and other request-related details. But the view function doesn’t need to declare a variable to auto-wire the request instance, just like in Django, because Flask has a built-in proxy object for it, the request object, which is part of the flask package. The following view function takes the username and password request parameters and checks if the credentials are in the database:

from __main__ import app
from flask import request, Response, render_template, redirect
from repository.user import validate_user
@app.route('/login/params')
def login_with_params():
    username = request.args['username']
    password = request.args['password']
    result = validate_user(username, password)
    if result:
      resp = Response(
       response=render_template('/main.html'), status=200, content_type='text/html')
      return resp
    else:
        return redirect('/error')

For instance, running the URL pattern of the given view function, http://localhost:5000/login/params?username=sjctrags&password=sjctrags2255, will provide us with sjctrags and sjctrags2255 as values when request.args['username'] and request.args['password'] are accessed, respectively.

Here is the complete list of objects and details that we can retrieve from the Request object through its request instance proxy:

  • request.args: Returns a MultiDict class that carries URL arguments or request parameters from the query string.
  • request.form: Returns a MultiDict class that contains parameters from an HTML form or JavaScript’s FormData object.
  • request.data: Returns request data in a byte stream that Flask couldn’t parse to form parameters and values due to an unrecognizable mime type.
  • request.files: Returns a MultiDict class containing all file objects from a form with enctype=multipart/form-data.
  • request.get_data(): This function returns the request data in byte streams before calling request.data.
  • request.json: Returns parsed JSON data when the incoming request has a Content-Type header of application/json.
  • request.method: Returns the HTTP method name.
  • request.values: Returns the combined parameters of args and form and encounters collision problems when both args and form carry the same parameter name.
  • request.headers: Returns request headers included in the incoming request.
  • request.cookies: Returns all the cookies that are part of the request.

The following view function utilizes some of the given request objects to perform an HTTP GET operation to fetch a user login application through an ID value and an HTTP POST operation to retrieve the user details, approve its preferred user role, and save the login details as new, valid user credentials:

from __main__ import app
from flask import render_template
from model.candidates import AdminUser, CounselorUser, PatientUser
from urllib.parse import parse_qsl
@app.route('/signup/approve', methods = ['POST'])
@app.route('/signup/approve/<int:utype>',methods = ['GET'])
def signup_approve(utype:int=None):
    if (request.method == 'GET'):
        id = request.args['id']
        user = select_single_signup(id)
        … … … … … … …
    else:
        utype = int(utype)
        if int(utype) == 1:
            adm = request.get_data()
            adm_dict = dict(parse_qsl(adm.decode('utf-8')))
            adm_model = AdminUser(**adm_dict)
            user_approval_service(int(utype), adm_model)
        elif int(utype) == 2:
            cnsl = request.get_data()
            cnsl_dict = dict(parse_qsl(
                   cnsl.decode('utf-8')))
            cnsl_model = CounselorUser(**cnsl_dict)
            user_approval_service(int(utype), cnsl_model)
        elif int(utype) == 3:
            pat = request.get_data()
            pat_dict = dict(parse_qsl(pat.decode('utf-8')))
            pat_model = PatientUser(**pat_dict)
            user_approval_service(int(utype), pat_model)
        return render_template('approved_user.html', message='approved'), 200

Our application has a listing view that renders hyperlinks that can redirect users to this signup_approve() form page with a context variable id, a code for a user type. The view function retrieves the variable id through request.args, checks what the user type id is, and renders the appropriate page based on the user type detected. The function also uses request.method to check if the user request will pursue either the GET or POST transaction since the given view function caters to both HTTP methods, as defined in its dual route declaration. When clicking the Submit button on the form page, its POST transaction retrieves all the form parameters and values in a byte stream type via request.get_data(). It is decoded to a query string object and converted into a dictionary by parse_sql from the urllib.parse module.

Now, if Flask can handle the request, it can also manage the outgoing response from the view functions.

Creating the response object

Flask uses Response to generate a client response for every request. The following view function renders a form page using the Response object:

from flask import render_template, request, Response
@app.route('/admin/users/list')
def generate_admin_users():
    users = select_admin_join_user()
    user_list = [list(rec) for rec in users]
    content = '''<html><head>
                    <title>User List</title>
            </head><body>
                    <h1>List of Users</h1>
                    <p>{}
            </body></html>
           '''.format(user_list)
    resp = Response(response=content, status=200, content_type='text/html')
    return resp

Response is instantiated with its required constructor parameters and returned by the view function as a response object. The following are the required parameters:

  • response: Contains the content that needs to be rendered either in a string, byte stream, or iterable of either of the two types.
  • status: Accepts the HTTP status code as an integer or string.
  • content_type: Accepts the mime type of the response object that needs rendering.
  • headers: A dictionary that contains the response header(s) that is/are necessary for the rendition process, such as Access-Control-Allow-Origin, Content-Disposition, Origin, and Accept.

But if the purpose is to render HTML pages, Flask has a render_template() method that references an HTML template file that needs rendering. The following route function, signup_users_form(), yields the content of a signup page – that is, add_signup.html from the /pages template folder – for new user applicants:

@app.route('/signup/form', methods= ['GET'])
def signup_users_form():
    resp = Response(  response=render_template('add_signup.html'), status=200, content_type="text/html")
    return resp

render_template() returns HTML content with its context data, if there is any, as a string. To simplify the syntax, Flask allows us to return the method’s result and the status code instead of the Response instance since the framework can automatically create a Response instance from these details. Like the previous examples, the following signup_list_users() uses render_template() to show the list of new user applications subject to admin approval:

@app.route('/signup/list', methods = ['GET'])
def signup_list_users():
    candidates = select_all_signup()
    return render_template('reports/list_candidates.html', records=candidates), 200

The given code emphasizes that render_template() can accept and pass context data to the template page. The candidates variable in this snippet handles an extracted list of records from the database needed by the template for content generation using the Jinja2 engine.

Jinja2

Jinja2 is Python’s fast, flexible, robust, expressive, and extensive templating engine for creating HTML, XML, LaTeX, and other supported formats for Flask’s rendition purposes.

On the other hand, Flask has a utility called make_response() that can modify the response by changing headers and cookies before sending them to the client. This method is suitable when the base response frequently undergoes some changes in its response headers and cookies. The following code modifies the content type of the original response to XLS with a given filename – in this case, question.xls:

@app.route('/exam/details/list')
def report_exam_list():
    exams = list_exam_details()
    response = make_response( render_template('exam/list_exams.html', exams=exams), 200)
    headers = dict()
    headers['Content-Type'] = 'application/vnd.ms-excel'
    headers['Content-Disposition'] = 'attachment;filename=questions.xls'
    response.headers = headers
    return response

Flask will require additional Python extensions when serializing and yielding PDF, XLSX, DOCX, RTF, and other complex content types. But for old and simple mime type values such as application/msword and application/vnd.ms-excel, Flask can easily and seamlessly serialize the content since Python has a built-in serializer for them. Other than mime types, Flask also supports adding web cookies for route functions. The following assign_exam() route shows how to add cookies to the response value that renders a form for scheduling and assigning counseling exams for patients with their respective counselors:

@app.route('/exam/assign', methods=['GET', 'POST'])
def assign_exam():
    if request.method == 'GET':
        cids = list_cid()
        pids = list_pid()
        response = make_response( render_template('exam/assign_exam_form.html', pids=pids, cids=cids), 200)
        response.set_cookie('exam_token', str(uuid4()))
        return response, 200
    else:
        id = int(request.form['id'])
        cid = request.form['cid']
        pid = int(request.form['pid'])
        exam_date = request.form['exam_date']
        duration = int(request.form['duration'])
        result = insert_question_details(id=id, cid=cid, pid=pid, exam_date=exam_date, duration=duration)
        if result:
            task_token = request.cookies.get('exam_token')
            task = "exam assignment (task id {})".format(task_token)
            return redirect(url_for('redirect_success_exam',        message=task ))
        else:
            return redirect('/exam/task/error')

The Response instance has a set_cookie() method that creates cookies before the view dispatches the response to the client. It also has delete_cookie(), which deletes a particular cookie before yielding the response. To retrieve the cookies, request.cookies has a get() method that can retrieve the cookie value through its cookie name. The given assign_exam() route shows how the get() method retrieves exam_cookie in its POST transaction.

Implementing page redirection

Sometimes, it is ideal for the route transaction to redirect the user to another view page using the redirect() utility method instead of building its own Response instance. Flask redirection requires a URL pattern of the destination to where the view function will redirect. For instance, in the previous assign_exam() route, the output of its POST transaction is not a Response instance but a redirect() method:

@app.route('/exam/assign', methods=['GET', 'POST'])
def assign_exam():
        … … … … … …
        if result:
            task_token = request.cookies.get('exam_token')
            task = "exam assignment (task id {})".format(task_token)
            return redirect(url_for('redirect_success_exam', message=task ))
        else:
            return redirect('/exam/task/error')

When the result variable is False, redirection to an error view called /exam/task/error will occur. Otherwise, the route will redirect to an endpoint or view name called redirect_success_exam. Every @route has an endpoint equivalent, by default, to its view function name. So, redirect_success_exam is the function name of a route with the following implementation:

@app.route('/exam/success', methods=['GET'])
def redirect_success_exam():
    message = request.args['message']
    return render_template('exam/redirect_success_view.html', message=message)

url_for(), which is used in the assign_exam() view, is a route handler that allows us to pass the endpoint name of the destination view to redirect() instead of passing the actual URL pattern of the destination. It can also pass context data to the Jinja2 template of the redirected page or values to path variables if the view uses a dynamic URL pattern. The redirect_success_exam() function shows a perfect scenario of context data passing, where it uses request.args to access a message context passed from assign_exam(), which is where the redirection call originated.

More content negotiations and how to serialize various mime types for responses will be showcased in the succeeding chapters, but in the meantime, let’s scrutinize the view templates of our route functions. View templates are essential for web-based applications because all form-handling transactions, report generation, and page generation depend on effective dynamic templates.

Implementing view templates

Jinja2 is the default templating engine of the Flask framework and is used to create HTML, XML, LaTeX, and markup documents. It is a simple, extensive, fast, and easy-to-use templating approach with powerful features such as layout capabilities, built-in programming constructs, support for asynchronous operations, context data filtering, and utility for unit testing.

Firstly, Flask requires all template files to be in the templates directory of the main project. To change this setting, the Flask() constructor has a template_folder parameter that can set and replace the default directory with another one. Our prototype, for instance, has the following Flask instantiation that overrides the default templates directory with a more high-level directory name:

from flask import Flask
app = Flask(__name__, template_folder='pages')

In our given setup, the view functions always refer to the pages directory when calling the template files through the render_template() method.

When it comes to syntax, Jinja2 has a placeholder ({{ }}) that renders dynamic content passed by the view functions to its template file. It also has a Jinja block ({% %}) that supports control structures such as loops, conditional statements, macros, and template inheritance. In the previous route function, assign_exam(), the GET transaction retrieves a list of counselor IDs (cids) and patient IDs (pids) from the database and passes them to the assign_exam_form.html template found in the exam subfolder of the pages directory. The following snippet shows the implementation of the assign_exam_form.html view template:

<!DOCTYPE html>
<html lang="en"><head><title>Patient's Score Form</title>
    </head><body>
        <form action="/exam/score" method="POST">
           <h3>Exam Score</h3>
           <label for="qid">Enter Questionnaire ID:</label>
           <select name="qid">
              {% for id in qids %}
                <option value="{{ id }}">{{ id }}</option>
              {% endfor %}
           </select><br/>
           <label for="pid">Enter patient ID:</label>
           <select name="pid">
              {% for id in pids %}
                <option value="{{ id }}">{{ id }}</option>
              {% endfor %}
           </select><br/>
           … … … … … …
           <input type="submit" value="Assign Exam"/>
        </form></body>
</html>

This template uses the Jinja block to iterate all the IDs and embed each in the <option> tag of the <select> component with the placeholder operator.

More about Jinja2 and Flask 3.x will be covered in Chapter 2, but for now, let’s delve into how Flask can implement the most common type of web-based transaction – that is, by capturing form data from the client.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Implement web and API applications using both standard and asynchronous Flask components
  • Improve your dev experience with signals, route decorators, async/await design patterns, context managers, and nested blueprints
  • Tie all the features together in each chapter through practical, relatable applications
  • Purchase of the print or Kindle book includes a free PDF eBook

Description

Flask is a popular Python framework known for its lightweight and modular design. Mastering Flask Web and API Development will take you on an exhaustive tour of the Flask environment and teach you how to build a production-ready application. You’ll start by installing Flask and grasping fundamental concepts, such as MVC and ORM database access. Next, you’ll master structuring applications for scalability through Flask blueprints. As you progress, you’ll explore both SQL and NoSQL databases while creating REST APIs and implementing JWT authentication, and improve your skills in role-based access security, utilizing LDAP, OAuth, OpenID, and databases. The new project structure, managed by context managers, as well as ASGI support, has revolutionized Flask, and you’ll get to grips with these crucial upgrades. You'll also explore out-of-the-box integrations with technologies, such as RabbitMQ, Celery, NoSQL databases, PostgreSQL, and various external modules. The concluding chapters discuss enterprise-related challenges where Flask proves its mettle as a core solution. By the end of this book, you’ll be well-versed with Flask, seeing it not only as a lightweight web and API framework, but also as a potent problem-solving tool in your daily work, addressing integration and enterprise issues alongside Django and FastAPI.

Who is this book for?

This book is for proficient Python developers seeking a deeper understanding of the Flask framework as a solution for tackling enterprise challenges. It is also a great resource for Flask-savvy readers eager to learn more about the framework’s advanced capabilities and new features.

What you will learn

  • Prepare, set up, and configure development environments for both API and web applications
  • Explore built-in serializers and encoders that processes request and response data
  • Solve big data issues by integrating Flask applications with NoSQL databases
  • Apply various ORM and ODM techniques to build model and repository layers
  • Integrate with OpenAPI, Circuit Breaker, ZooKeeper, and OpenTracing to build scalable API applications
  • Use Flask middleware to provide CRUD transactions for Flutter-based mobile applications
Estimated delivery fee Deliver to Romania

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 16, 2024
Length: 494 pages
Edition : 1st
Language : English
ISBN-13 : 9781837633227
Languages :
Concepts :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Estimated delivery fee Deliver to Romania

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

Product Details

Publication date : Aug 16, 2024
Length: 494 pages
Edition : 1st
Language : English
ISBN-13 : 9781837633227
Languages :
Concepts :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 91.97
FastAPI Cookbook
€33.99
Mastering Flask Web and API Development
€29.99
Full-Stack Web Development with TypeScript 5
€27.99
Total 91.97 Stars icon

Table of Contents

17 Chapters
Part 1:Learning the Flask 3.x Framework Chevron down icon Chevron up icon
Chapter 1: A Deep Dive into the Flask Framework Chevron down icon Chevron up icon
Chapter 2: Adding Advanced Core Features Chevron down icon Chevron up icon
Chapter 3: Creating REST Web Services Chevron down icon Chevron up icon
Chapter 4: Utilizing Flask Extensions Chevron down icon Chevron up icon
Part 2:Building Advanced Flask 3.x Applications Chevron down icon Chevron up icon
Chapter 5: Building Asynchronous Transactions Chevron down icon Chevron up icon
Chapter 6: Developing Computational and Scientific Applications Chevron down icon Chevron up icon
Chapter 7: Using Non-Relational Data Storage Chevron down icon Chevron up icon
Chapter 8: Building Workflows with Flask Chevron down icon Chevron up icon
Chapter 9: Securing Flask Applications Chevron down icon Chevron up icon
Part 3:Testing, Deploying, and Building Enterprise-Grade Applications Chevron down icon Chevron up icon
Chapter 10: Creating Test Cases for Flask Chevron down icon Chevron up icon
Chapter 11: Deploying Flask Applications Chevron down icon Chevron up icon
Chapter 12: Integrating Flask with Other Tools and Frameworks Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon