Ep.11 Query strings in Flask

Query strings in Flask | Learning Flask Ep. 11

Creating, serializing and working with query string data in Flask

In this part of the “Learning Flask” series, we’re going to working with query strings. A query string is part of the URL as a string of parameters and values and are used ubiquitously across the web.

Query strings are essentially a string of key/value pairs sent by the client to the server.

Here’s an example of a query string in the URL from a quick Google search for query string:

https://www.google.com/search?q=query+string

Let’s break down the URL:

  • https is the protocol
  • www.google.com is the domain
  • /search is the path
  • ?q=query+string is the query string

Anatomy of a query string

Focusing on the query string element of the URL, we see the following components:

  • ? starts the query string
  • q is the first parameter
  • = separates/assigns a value to the parameter
  • query+string is the value assigned to the q parameter

You’ll notice the + substitution between “query string”. This is because the space charactes is not allowed in a URL so must be replaced with something else.

Spaces in query strings are replaced with + or %20

Let’s take a look at a slightly more complex query string, again from a Google search for “flask”:

https://www.google.com/search?q=flask&oq=flask&sourceid=chrome&ie=UTF-8

If you take a closer look at the query string, you’ll see multiple parameters and values, separated by the & symbol.

We use & to separate parameters and values in the query string. Let’s create a query string below with a few sets of params & values:

http://127.0.0.1:5000/query?foo=foo&bar=bar&baz=baz&title=query+strings+with+flask

Let’s use this query string in our Flask application and learn how to work with it!

Flask query strings

First up, let’s create a new route with the URL /query:

app/app/views.py

@app.route("/query")
def query():
    return "No query string received", 200

If you got to /query in your browser, you’ll see No query string received in your window.

Go ahead and paste the query string we just created above into your browser URL bar and see what happens.

You’ll notice we don’t get any errors, however we’re not yet doing anything with our query string. Let’s go ahead and serialize it!

Serializing query strings

To work with any kind of request object or data, we need to import request from flask:

app/app/views.py

from flask import request

Just like we’ve used request.form for serializing form data and request.get_json() to serialize incoming JSON data, we use request.args to parse and serialize the query string into a Python object.

Let’s store our query string object as a variable called args and print them:

app/app/views.py

@app.route("/query")
def query():

    args = request.args

    print(args)

    return "No query string received", 200

Save and reload that same URL with the query string, you’ll see the following in your terminal:

ImmutableMultiDict([('foo', 'foo'), ('bar', 'bar'), ('baz', 'baz'), ('title', 'query strings with flask')])

request.args has parsed our query string and conveniently converted it into an ImmutableMultiDict which we can treat just like a Python dictionary, for example, change print(args) for the following:

app/app/views.py

for k, v in args.items():
    print(f"{k}: {v}")` 

You’ll see our keys and values printed out to the console:

foo: foo
bar: bar
baz: baz
title: query strings with flask` 

Just like a dictionary, we can now pluck out values by their key:

@app.route("/query")
def query():

    args = request.args

    if "foo" in args:
        foo = args["foo"]

    if "bar" in args:
        bar = args.get("bar")

    if "baz" in args:
        baz = args["baz"]

    if "title" in request.args:
        title = request.args.get("title")

    print(foo, bar, baz, title)

    return "No query string received", 200

However at this point we’ll get an error if we don’t send a query string with values for foo, bar, baz and title.

Let’s refactor our code to mitigate any potantial errors and return a formatted query string to the client:

@app.route("/query")
def query():

    if request.args:

        # We have our query string nicely serialized as a Python dictionary
        args = request.args

        # We'll create a string to display the parameters & values
        serialized = ", ".join(f"{k}: {v}" for k, v in request.args.items())

        # Display the query string to the client in a different format
        return f"(Query) {serialized}", 200

    else:

        return "No query string received", 200

If you re-submit the URL, you’ll see:

(Query) foo: foo, bar: bar, baz: baz, title: query strings with flask

And that pretty much wraps things up for query strings with Flask!

Extras

Although I’ve not found much use for them in the past, the request object also provides us with a few more features for working with query strings.

request.query_string will return the query string, for example:

@app.route("/query")
def query():

    print(request.query_string)

    return "Thanks", 200

Will return:

b'foo=foo&bar=bar&baz=baz&title=query+strings+with+flask'

request.values will return a CombinedMultiDict which comines args with form, for example:

@app.route("/query")
def query():

    print(request.values)

    return "Thanks", 200` 

Returns:

CombinedMultiDict([ImmutableMultiDict([('foo', 'foo'), ('bar', 'bar'), ('baz', 'baz'),   
('title', 'query strings with flask')]), ImmutableMultiDict([])]) 

Not something I’ve used in the past but can imagine it would be useful to submit a form with query string parameters in the URL.

Wrapping up

Query strings are a convenient way to pass arguments to your application and Flask makes light work of quickly parsing them into something we can work with.

POST requests don’t typically include a query string as they tend to include data that you want to keep within the request body, so you’ll mostly be using them with GET requests.

Last modified · 28 Feb 2019

Written with StackEdit.