Python Flask framework @ app. route usage tutorial, flask@app.route

Source: Internet
Author: User

Python Flask framework @ app. route usage tutorial, flask@app.route

In my previous article, I built a framework to simulate the behavior of the first example on the Flask Website "@ app. route.

If you miss the article "this is not magic", click here.

In this article, we plan to slightly tune the high difficulty and add variable parameters to our URLs. At the end of this article, we will support the behavior expected by the following code segments.

 app = Flask(__name__) @app.route("/hello/<username>")def hello_user(username):  return "Hello {}!".format(username)

In this way, the following path instance (path ):
/Hello/ains
The above path will be matched, and the output to us is
Hello ains!

Express our path in the form of regular expressions.

Now we will allow dynamic changes to our URLs, and we will no longer be able to directly compare the paths registered using "@ app. route ()" with the path instance.

What will we use to replace it? We need to use a regular expression, so that we can match the path as a pattern, instead of comparing it with a fixed string.

I am not going to discuss the details of Regular Expressions in this article, but if you need a review, you can click this website.

Then, our first step is to convert our path to the regular expression mode so that we can match the input path instance. We will also use this regular expression to extract the variables we are interested in.

What is the length of the regular expression that matches the path "/hello?

A simple regular expression such as "^/hello/(. +) $" is a good start. Let's take a look at how it works with the code:

 import re route_regex = re.compile(r"^/hello/(.+)$")match = route_regex.match("/hello/ains") print match.groups()

The output is as follows:
('Ains ',)

Yes, but ideally we want to maintain the first group of links we have matched and identify "username" from the path "/hello ".

Naming capture group

Fortunately, regular expressions also support naming and capturing groups, allowing us to assign a name to a matching group, and we can retrieve it after reading our matching.

We can use the following symbol to give the first example to identify the capture group of "username.
 

/hello/(<?P<username>.+)"

Then we can use the groupdict () method for our regular expression to treat all capture groups as a dictionary, and the group names correspond to matching values.

The following code is provided:
 

route_regex = re.compile(r'^/hello/(?P<username>.+)$')match = route_regex.match("/hello/ains") print match.groupdict()

The following dictionary is output for us:
{'Username': 'ains '}

Now, with the regular expression format we need and how to use them to match the input URLs, the last thing left is to write a method, convert the declared paths to their equivalent regular expression patterns.

To do this, we will use another regular expression (then it will be all regular expressions). to convert the variables in our path to the regular expression mode, here we will convert "" into "(? P. + )".

It sounds too simple! We can implement it with only one new line of code.

 def build_route_pattern(route):  route_regex = re.sub(r'(<w+>)', r'(?P1.+)', route)  return re.compile("^{}$".format(route_regex)) print build_route_pattern('/hello/<username>')

Here we use a regular expression to represent all the modes that appear (a string contained in angle brackets), which is equivalent to its regular expression naming group.

The first parameter of re. sub is placed in parentheses to assign it to the first matching group. In our second parameter, we can use the content of the first matching group by writing 1 (2 will be the content of the second matching group, and so on .......)

Then, the input mode
 

/hello/<username>

The regular expression will be given:
 

^/hello/(?P<username>.+)$

Innovation

Let's take a look at the simple NotFlask class we wrote last time.
 

class NotFlask():  def __init__(self):    self.routes = {}   def route(self, route_str):    def decorator(f):      self.routes[route_str] = f      return f     return decorator   def serve(self, path):    view_function = self.routes.get(path)    if view_function:      return view_function()    else:      raise ValueError('Route "{}"" has not been registered'.format(path)) app = NotFlask() @app.route("/")def hello():  return "Hello World!"

Now we have a new improvement method to match the input path. We intend to remove the native dictionary we used in the previous implementation.

Let's start with the transformation of our function to facilitate the addition of paths, so that we can use (pattern, view_function) to replace the list to save our path in the dictionary.

This means that when a programmer uses @ app. route () describe a function. We will try to compile their path into a regular expression and store it as a decoration function in our new path list.

Let's look at the implementation code:

 class NotFlask():  def __init__(self):    self.routes = []   # Here's our build_route_pattern we made earlier  @staticmethod  def build_route_pattern(route):    route_regex = re.sub(r'(<w+>)', r'(?P1.+)', route)    return re.compile("^{}$".format(route_regex))   def route(self, route_str):    def decorator(f):      # Instead of inserting into a dictionary,      # We'll append the tuple to our route list      route_pattern = self.build_route_pattern(route_str)      self.routes.append((route_pattern, f))       return f     return decorator

We also plan to need a get_route_match method, and give it a path instance. We will try and find a matched view_function, or return None if one cannot be found.

However, if a match is found, in addition to view_function, we also need to return something that contains the dictionary of the previously captured matching group, we need it to pass correct parameters for the view function.

Well, our get_route_match will be long like this:

 def get_route_match(path):  for route_pattern, view_function in self.routes:    m = route_pattern.match(path)    if m:      return m.groupdict(), view_function   return None

Now we are almost done. The last step is to find out the method for calling view_function and use the regular expression to match the correct parameters of the group dictionary.

Several Methods for calling a function

Let's review how different methods call a python function.

For example:

 def hello_user(username):  return "Hello {}!".format(username)

The simplest (perhaps as you are familiar with) method is to use regular parameters, where the order of parameters matches the order of the functions we define.

>>> hello_user("ains")Hello ains!

Another way to call a function is to use a keyword parameter. Keyword parameters can be specified in any order and are suitable for functions with many optional parameters.

>>> hello_user(username="ains")Hello ains!

In Python, the last method to call a function is to use the keyword parameter dictionary, which corresponds to the parameter name. We told Python to unpack a dictionary and use two asterisks "**" to treat it as a function's keyword parameter. The following code snippet is exactly the same as the code snippet above. Now we can use dictionary parameters to dynamically create it at runtime.

>>> kwargs = {"username": "ains"}>>> hello_user(**kwargs)Hello ains!

Okay, remember the groupdict () method above? Is that the guy who returns {"username": "ains"} after the regular expression matches? Now that we understand kwargs, we can easily pass dictionary matching to our view_function to complete NotFlask!

So let's put all these into our final class.
 

class NotFlask():  def __init__(self):    self.routes = []   @staticmethod  def build_route_pattern(route):    route_regex = re.sub(r'(<w+>)', r'(?P1.+)', route)    return re.compile("^{}$".format(route_regex))   def route(self, route_str):    def decorator(f):      route_pattern = self.build_route_pattern(route_str)      self.routes.append((route_pattern, f))       return f     return decorator   def get_route_match(self, path):    for route_pattern, view_function in self.routes:      m = route_pattern.match(path)      if m:        return m.groupdict(), view_function     return None   def serve(self, path):    route_match = self.get_route_match(path)    if route_match:      kwargs, view_function = route_match      return view_function(**kwargs)    else:      raise ValueError('Route "{}"" has not been registered'.format(path))

Next, let's see the following code snippet to witness a miracle:

 app = NotFlask() @app.route("/hello/")def hello_user(username):return "Hello {}!".format(username) print app.serve("/hello/ains")

We will get the output:

Hello ains!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.