A tutorial on @app.route usage in Python's flask framework _python

Source: Internet
Author: User
Tags in python

In my last article, I built a framework to simulate the behavior of the first example of "@app. Route ('/") on the Flask website.

If you miss the "This is not magic", please click here.

In this article, we intend to slightly increase the difficulty of adding variable parameters to our URLs, and at the end of this article we will support the behavior expected by the code snippet below.

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

The following path instance (path):
/hello/ains
Will match the above path and give us the output as
Hello ains!

Express our paths in regular form.

Now we're going to allow our URLs to change dynamically, and we no longer have the ability to compare directly to the path instance with the path previously registered using the @app. Route ().

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

I'm not going to start discussing the details of regular expressions in this article, but if you need a review, you can click on the site.

Our first step, then, is to convert our paths into regular expression patterns so that we can match them when we enter the path instance. We will also use this regular expression to extract the variables we are interested in.

So what does a regular expression that matches the path "/hello/" look like?

Well, a simple regular expression like "^/hello/(. +) $" will be a good start, let's see how it works with the code:

 
import re
 
Route_regex = Re.compile (r "^/hello/(. +) $")
match = Route_regex.match ("/hello/ains")
 
print Match.Groups ()

will be output:
(' Ains ',)

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

Named Capture Group

Fortunately, the regular expression also supports named Capture groups, allowing us to assign a name to the matching group, and we can retrieve it after reading our match.

We can use the following notation to give the first example to identify the capturing group of "username".

/hello/. p<username>.+) "

We can then use the Groupdict () method on our regular expressions to treat all the capturing groups as a dictionary, and the group names correspond to the values on the matches.

Then we give the following code:

Route_regex = Re.compile (R ' ^/hello/) (? p<username>.+) $ ')
match = Route_regex.match ("/hello/ains")
 
print match.groupdict ()

The following dictionaries will be exported for us:
{' username ': ' ains '}

Now, with the format of the regular expressions we need, and how to use them to match the knowledge of the input URLs, the last thing left is to write a method that converts our declared paths into their equivalent regular expression patterns.

To do this we will use another regular expression (followed by a full regular expression), and in order for the variable in our path to be converted to a regular representation pattern, here as a demonstration we'll "convert" (?). p.+) ".

It sounds too easy! We will be able to implement it with just 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 representing all occurrences of the pattern (a string contained within the angle bracket), which is equivalent to its regular expression-named group.

Re.sub First argument we put our pattern in parentheses to assign it to the first matching group. In our second argument, we can use the contents of the first match Group by writing 1 (2 will be the content of the second matching group, etc. ...)

So finally, the input mode

/hello/<username>

will give us regular expressions:

^/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 that we have a new improved method to match the input path, we intend to remove the native dictionaries we used in the previous version of the implementation.

Let's start by transforming our functions so that we can add paths so that we could save our paths with a list instead of a dictionary (pattern, view_function).

This means that when a programmer uses @app.route () to decorate a function, we will try to compile their path into a regular expression and then store it, belonging to a decorative 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 = SE Lf.build_route_pattern (ROUTE_STR)
      self.routes.append ((Route_pattern, F)) return
 
      F return
 
    decorator

We also intend to need a get_route_match method that gives it an instance of the path, will try and find a matching view_function, or return none if one is not found.

However, if a match is found, we need to return something other than view_function, that is, we include the dictionary that captured the matching group before, and we need it to pass the correct arguments for the view function.

All right, our get_route_match is probably 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 that we're almost done, the final step will be to find a way to invoke View_function, using the correct arguments from the regular expression to match the group Dictionary.

Several ways to call a function

Let's review the different methods of invoking a Python function.

Like this:

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

The simplest (and perhaps the most familiar) approach is to use regular arguments, where the order of the parameters matches the order of those 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!

The last way to invoke a function in Python is to use the keyword parameter dictionary, the dictionary keyword corresponding to the parameter name. We told Python to unpack a dictionary and use the two asterisk "* *" as the keyword parameter of the function. The following code snippet is exactly the same as the preceding code snippet, and now we use the dictionary parameter, we can create it dynamically at runtime.

>>> Kwargs = {"username": "Ains"}
>>> Hello_user (**kwargs)
Hello ains!

Well, remember the Groupdict () method above? Is that the same guy who returns {"username" after a regular expression completes a match: "Ains"}? So now that we know Kwargs, we can easily match our View_function pass dictionary, complete notflask!

So let's cram this 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, is the moment to witness miracles, see the following code snippet:

 
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.