Flask视图和URL

Posted Flask学习笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask视图和URL相关的知识,希望对你有一定的参考价值。

                      

URL重定向和url_for

1.url_for

这个函数接受视图函数的名称(字符串的形式),返回视图函数对应的URL

语法:

 url_for(endpoint, **values)
  • endpoint:节点,指代视图函数

  • values:关键字参数,对应视图函数中的变量

例子:

 #!/usr/bin/env python
 # coding=utf-8
 
 
 from flask import Flask
 from flask import url_for
 
 # 初始化
 app = Flask(__name__)
 
 
 # 路由
 
 @app.route('/')
 def index():
     return  'index page!'
 
 @app.route('/login/<uname>/<upasswd>')
 def login(uname,upasswd):
     return  'welcome'
 
 @app.route('/get/')
 def get_url():
     my_url = url_for("login", uname='Jack', upasswd='123')
     return  my_url
 
 
 if __name__ == '__main__':
     app.run(debug = True)

返回的是一个标准的url路径。

2.redirct重定向

跳转到指定的URL,和url_for()一起使用

 return redirct(my_url)

浏览器由一个路径跳转到另外的路径,这就是重定向,典型的如用户登录页面的跳转。

  • 永久性重定向:HTTP代码是301

  • 暂时性重定向: HTTP代码是302.

例子:

 #!/usr/bin/env python
 # coding=utf-8
 
 from flask import Flask
 from flask import redirect,url_for
 
 app = Flask(__name__)
 
 @app.route('/login/')
 def login():
     info = """
    <html>
        <head>
 
        </head>
        <body>
            <div>
            <input type="button", value="name">
            <input type="text", value="">
            <input type="button", value="passwd">
            <input type="text", value="">
            <input type="button", value="submit">
            </div>
        </body>
    </html>
    """
     return info
 
 @app.route('/')
 def index():
     Url = url_for('login')
     return redirect(Url)
 
 if __name__ == "__main__":
     app.run(debug=True)
 


3.版本控制

 $  git log
 $  git status
 $  git add .
 $  git commit -m "add url_for,redirect.v1.005"
 $  git status

4.在动态路由中自定义URL转换器

现在我们已经知道了,在动态路由的时候,有很多的converter,比如int,float,string,path,uuid等等。当然,也可以自定义一个转换器,只要满足相应的规则即可。

  • 导入转换器继承类:from werkzeug.routing import BaseConverter

  • 自定义一个转换器,继承自BaseConverter类。

  • 映射到URL转换器的默认字典中:app.url_map.converter['key'] = value

  • 使用自定义转换器

1.定制转换器只使用正则表达式

例子:

 #!/usr/bin/env python
 # conding = utf-8
 
 
 from flask import Flask
 # 导入继承类
 from werkzeug.routing import BaseConverter
 
 # 初始化
 app = Flask(__name__)
 
 
 # 自定义一个转换器
 class TelphoneConverter(BaseConverter):
  regex = r'1[3-9][0-9]{9}'
 
 # 映射转换器字典
 app.url_map.converters['tel'] = TelphoneConverter
 
 # 使用自定义转换器
 @app.route('/tel/<tel:tel_num>/')
 def phoneNum(tel_num):
  return 'welcome:{}'.format(tel_num)
 
 if __name__ == '__main__':
  app.run(debug = True)

访问匹配到正则的号码可以看到界面,反之则不行

Flask视图和URL(二)

Flask视图和URL(二)

2.定制转换器复杂化

定制转换器中可以实现方法to_pythonto_url.

  • to-python:强化正则表达式,进行额外的验证,将匹配到的字符串转换为其他对象.并且应该引发一个werkzeug.routing.ValidationError 错误,web会返回500 错误.

  • to_url:在构建URL时将Python对象转换为字符串. 此处引发的任何错误都将转换为werkzeug.routing.BuildError并最终导致500错误

解释例子:假设当前有一个购物网站,有2名会员登录,一个采购了2本书,另外一个采购了2件衣服,网站上还有很多的笔记本和台式机等物品。

 #!/usr/bin/env python
 # coding=utf-8
 
 # 数据库
 
 books_information = {
     'python': 18,
     'java': 19,
     'c++': 20,
     'c': 21
 }
 
 clothes_information = {
     'red': 18,
     'block': 19,
     'yellow': 20
 }
 
 pcs_information = {
     'hp': 18,
     'dell': 19,
     'alien': 20
 }
 
 vips_information = {
     '18818808891',
     '18818808899'
 }
 
 # 采购信息对应
 from flask import Flask
 from werkzeug.routing import BaseConverter
 
 app = Flask(__name__)
 
 class Phone_Coverter(BaseConverter):
     """手机号的正则转换"""
         regex = r'1(([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}'
 
 # 注册到URL转换器中
 app.url_map.converter['phone'] = Phone_Coverter
 
 @app.route('/')
 def index():
     return "Shopping web"
 
 @app.route('/<phone:my_phone>')
 def handle_phone(my_phone):
     if my_phone in vips_information:
         return 'welcome VIP:{}'.format(my_phone)
     else:
         return 'please register'
 
 # 会员购买信息
 # 会员购买信息
 @app.route('/18818808891/<book_name>/')
 def books_detail(book_name):
     if book_name == 'python':
         return 'This book is {} and price is {}'.format(book_name, str(book_informathion[book_name]))
     elif book_name == 'java':
         return 'This book is {} and price is {}'.format(book_name, str(book_informathion[book_name]))
     elif book_name == 'python+java':
         book_name = book_name.split('+')
         return 'The book is {} and {}'.format(book_name[0], book_name[1])
     else:
         return 'Not this book'
 
 @app.route('/18818808899/<clothes_name>/')
 def clothes_detail(clothes_name):
     if clothes_name == 'red':
         return 'The clothes color is {}, price is {}'.format(clothes_name, str(clothes_information[clothes_name]))
     elif clothes_name == 'black':
         return 'The clothes color is {}, price is {}'.format(clothes_name, str(clothes_information[clothes_name]))
     elif clothes_name == 'red+black':
         clothes_name = clothes_name.split('+')
         return 'The clothes is {} and {}'.format(clothes_name[0], clothes_name[1])
     else:
         return 'Not this clothes'
 
 @app.route('/get/18818808891/')
 def get_books_detail():
     info = url_for('books_detail', book_name='python+java')
     return info
 
 @app.route('/get/18818808899/')
 def get_clothes_detail():
     info = url_for('clothes_detail', clothes_name='red+black')
     return info
 
 
 
 
 if __name__=='__main__':
     app.run(debug=True)

但是这样有一个问题就是,假如会员3有新的2个物品比如pc机器,就需要从新写一下split() 方法,如果有非常多的数据就会很不方便.

python是面向对象语言,那么我们就可以把相同的抽离出去.

自定义继承的类BaseConverter 默认提供了2个方法to_python,to_url 就可以来处理上面的问题,我们只需要在自己写的类中重写这两个方法就可以.

 
 # 自定义处理split
 class Handle_List(BaseConverter):
     """自定义处理A+B"""
     # regex =
     def to_python(self, value):
         """转换url为其他对象"""
         print(value)
         return value.split('+')
 
     def to_url(self, value):
         """转换其他对象为url"""
         print(value)
         if type(value) == str:
             return value
         else:
             return '+'.join(value)
 
 # 注册到默认URL转换器中
 app.url_map.converters['hlist'] = Handle_List

最后写出来的效果是:

 # 数据库,实物和价格的对应
 books_information = {
  'python': 18,
  'java': 19,
  'c++': 20,
  'c': 21
 }
 
 clothes_information = {
  'red': 18,
  'black': 19,
  'yellow': 20
 }
 
 pcs_information = {
  'hp': 18,
  'dell': 19,
  'alien': 20
 }
 
 vips_information = {
  '18818808891',
  '18818808899'
 }
 
 
 # 实现每个会员自己的采购信息
 
 from flask import Flask,url_for
 from werkzeug.routing import BaseConverter
 
 app = Flask(__name__)
 
 @app.route('/')
 def index():
  return '购物网站'
 
 # 自定义Phone类
 class Phone_Coverter(BaseConverter):
  """手机号的正则表达式"""
  regex = r'1(([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}'
 
 # 添加到默认URL转换器中
 app.url_map.converters['phone'] = Phone_Coverter
 
 
 # 自定义处理split
 class Handle_List(BaseConverter):
  """自定义处理A+B"""
  # regex =
  def to_python(self, value):
      """转换url为其他对象"""
      print(value)
      return value.split('+')
 
  def to_url(self, value):
      """转换其他对象为url"""
      print(value)
      if type(value) == str:
          return value
      else:
          return '+'.join(value)
 
 # 注册到默认URL转换器中
 app.url_map.converters['hlist'] = Handle_List
 
 
 @app.route('/<phone:my_phone>/')
 def handle_phone(my_phone):
  if my_phone in vips_information:
      return 'welcome VIP:{}'.format(my_phone)
  else:
      return 'Please register'
 
 # 会员购买信息
 @app.route('/18818808891/<hlist:book_name>/')
 def books_detail(book_name):
  return 'The books is {}'.format(book_name)
 
 @app.route('/18818808899/<hlist:clothes_name>/')
 def clothes_detail(clothes_name):
  return 'The clothes color is {}'.format(clothes_name)
 
 
 @app.route('/get/18818808891/')
 def get_books_detail():
  info = url_for('books_detail', book_name='python+java')
  return info
 
 @app.route('/get/18818808899/')
 def get_clothes_detail():    
  # 处理 to_url
  info = url_for('clothes_detail', clothes_name=['red', 'black'])
  return info
 
 
 if __name__ == '__main__':
  app.run(debug=True)

访问http://127.0.0.1:5000/18818808891/python+java/

 The books is ['python', 'java']

访问http://127.0.0.1:5000/18818808899/red+black/

 The clothes color is ['red', 'black']

5.版本控制

 $ git add .
 $ git commit -m "add 定制转换器。v1.006"

6.视图函数Response

Response:指响应,指的是客户端发送给服务器请求信息后(getpost),服务器反馈给客户端的行为就是响应。

比如,新建一个简单的站点,通过浏览器查看响应信息。

 from flask import Flask, Response
 # from werkzeug.wrappers import Response
 
 app = Flask(__name__)
 
 
 @app.route('/')
 def index():
  return 'The Response object'
 
 
 @app.route('/response/')
 def my_response():
  return Response('The Response object')
 
 
 if __name__ == '__main__':
  app.run(debug=True)

通过浏览器查看:

1.FlaskResponse的置换逻辑

Response 其实来自于werkzeug 中的定义,导入的方式可以有2种

 from flask import Flask, Response
 from werkzeug.wrappers import Response

根据定义来看,在Flask中:

  • 如果返回的是一个合法的Response对象,直接返回

  • 如果返回的是一个字符串,Flask会重新创建一个werkzeug.wrapper.Resonse() 对象.它会将字符串作为主体,状态码200 ,MIME类型为text/html 返回.

  • 如果返回的是一个元组,元组的数据类型是(Response, status, headers) ,status会更新状态码,hearder 可以是一个列表或者字典,作为额外的消息头

  • 如果返回的是一个字典,Flask 会自动返回一个json 字符串

  • 如果以上条件都不满足,Flask会假设返回值是一个合法的wsgi应用

  • 可以自定义响应方法force_type

2.自定义Response

自定义消息应该注意以下:

  • Response 子类: 自定义的类必须是Response 的子类

  • force_type: 实现方法force_type(cls,response,envison=None)==> 当返回的数据类型不是字符串和元组,Flask 会调用force_type 方法来处理,不能处理时就会报错,所以子类一般都会重写这个方法来处理自己的返回数据类型,从而返回返回合法的数据类型.参数response 就是传入的不合法数据.

  • response_class: 使用app.response_class=MyResponse生效

 from flask import Flask,Response,jsonify
 
 app = Flask(__name__)
 
 @app.route('/')
 def index():
     """Flask 内部会转回字符串"""
     return 'response object'
 
 @app.route('/tuple/')
 def my_tuple():
     """Flask 响应元组"""
     return Response('tuple:response object', 200)
 
 @app.route('/dict/')
 def my_dict():
     """Flask 字典会返回一个jison字符串"""
     user_information = {
         'name':'python',
         'price':'18'
    }
     return user_information
 
 @app.route('/list/')
 def my_list():
     """访问不支持的数据类型会报错"""
     user_list = ['python', 'java']
     return user_list
 
 if __name__ == "__main__":
     app.run(debug=True)

当在浏览器中访问http://127.0.0.1:5000/list/ 时,会弹出报错信息

 TypeError
 TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a list.

现在通过自定义Response 来处理list:

 """
 处理不支持的数据类型,自定义Response
 选择将列表转换为json字符串
 """
 
 class Handle_list_to_json(Response):
     """不改变类的前提下,修改实例数据"""
     @classmethod
     def force_type(cls, response, environ=None):
         """列表类型修改为json
        response:传入的实例数据,也就是不符合规范的数据"""
         print(response)
         if isinstance(response, list):
             # 注意变量变量明必须对应force_type中的变量名
              response = '+'.join(response)
         return super().force_type(response,environ)
 
 app.response_class = Handle_list_to_json
 
 @app.route('/list_to_json/')
 def dict_to_json():
     user_information = ['python', 'java', 'c']
     return Response(user_information)

再次访问的时候会正确的返回列表为字符串

3.jsonify 会将数据类型转换为json 字符串

 from flask import Flask,Response,jsonify
 
 app = Flask(__name__)
 
 @app.route('/json/<varriable>/')
 def varriable_to_json(varriable):
  a = [1, 2, 3]
  b = (1, 2)
  c = {'a':1, 'b':2}
  a, b, c = jsonify(a), jsonify(b), jsonify(c)
  if varriable == 'a':
      return a
  elif varriable == 'b':
      return b
  else:
      return c
 
 if __name__ == "__main__":
  app.run(debug=True)






以上是关于Flask视图和URL的主要内容,如果未能解决你的问题,请参考以下文章

flask路由和视图和cookie

Flask视图和URL

1.Flask URL和视图

Flask视图:视图函数,类视图,蓝图使用方法整理

flask的路由

Flask 视图函数和视图类