A tutorial on @app.route usage in the flask framework of Python

Source: Internet
Author: User
In my last article, I built a framework that simulates the behavior of the first example of "@app. Route ('/')" on the Flask website.

If you missed the "It's not Magic", please click here.

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

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

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

Express our path in a regular form.

Now we will allow our URLs to change dynamically, and we will no longer be able to compare the paths registered with previously used "@app. Route ()" directly with the path instance.

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

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

Our first step, then, is to turn our paths into regular expression patterns so that we can match when we enter the path instance. We will also use this regular expression to extract variables of interest to us.

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

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

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

The output will be:
(' Ains ',)

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

Naming capturing groups

Fortunately, the regular expression also supports named capturing 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 of a capturing group that identifies "username".

/hello/(<? P
 
  
   
  . +) "
 
  

Then we can use the Groupdict () method on our regular expression to treat all capturing groups as a dictionary with the names of the groups corresponding to the values on the match.

Then we give the following code:

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

Will output the following dictionaries 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 transforms the paths we declare into their equivalent regular expression patterns.

To do this we will use another regular expression (which will then be all regular expressions), in order for the variables in our path to be converted to a regular expression pattern, then here as a demonstration we'll "convert" to "(? p.+) ".

It sounds too easy! We will be able to implement it with just a single line of new code.

def build_route_pattern (route):  Route_regex = Re.sub (R ' (
 
  
   
  ) ', R ' (? p1.+) ', Route '  return re.compile ("^{}$". Format (Route_regex)) Print Build_route_pattern ('/hello/
  
   
    
   ' )
  
   
 
  

Here we use a regular expression to represent all occurrences of the pattern (a string enclosed in angle brackets), which is equivalent to its regular expression named group.

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

So finally, the input mode

/hello/
 
  

will give us the regular expression:

^/hello/(? P
 
  
   
  . +) $
 
  

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 ') {} "" have 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 are going to remove the native dictionary we used for 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 using (pattern, view_function) a list instead of a dictionary.

This means that when a programmer uses @app.route () to decorate a function, we are going to attempt to compile their path into a regular expression, and then store it, which belongs 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 ' (
 
  
   
  ) ', 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_pa Ttern = Self.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, give it a path instance, 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 besides view_function, that is, we have a dictionary that captures the matching group before, and we need it to pass the correct arguments for the view function.

Well, our get_route_match probably looks 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 the method that calls 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.

For example, like this:

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

The simplest (perhaps exactly what you know) approach is to use regular parameters, where the order of the arguments 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 call a function in Python is to use the keyword parameter dictionary, which corresponds to the name of the parameter in the dictionary. We tell Python to unpack a dictionary and use the two asterisk "* *" as the key parameter for the function. The following code snippet is exactly the same as the code snippet above, and now we use the dictionary parameter, which we can create dynamically at run time.

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

OK, remember the groupdict () method above? Is that the same guy who returned {"username": "Ains"} after the regular expression has finished matching? So now that we know Kwargs, we can easily pass the dictionary match to our view_function and complete the 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 ' (
 
  
   
  ) ', 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 ' {} ' "have not been Registered '. Format (path)
 
  

Next, the time to witness a miracle, 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!

  • Related Article

    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.