400 028 6601

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

PythonWeb开发:教你如何解放路由管理-创新互联

1. 痛点

随着业务的飞速发展,API接口越来越多,路由管理文件从几十号变成几百上千行,且每次上新服务,需要在修改路由文件代码,带来一定的风险。

创新互联服务项目包括历城网站建设、历城网站制作、历城网页制作以及历城网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,历城网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到历城省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

Python Web开发: 教你如何解放路由管理

2. 解决方案

2.2 代码实现

python很多框架的启动和路由管理都很类似,所以这套规则适合很多框架,测试过程中有包括flask, tornado, sanic, japronto。 以前年代久远的web.py也是支持的。

完整代码地址:
https://github.com/CrystalSkyZ/PyAutoApiRoute

  1. 实现下划线命名 转 驼峰命名 函数,代码演示:

    def underline_to_hump(underline_str):
    '''
    下划线形式字符串转成驼峰形式,首字母大写
    '''
    sub = re.sub(r'(_\w)', lambda x: x.group(1)[1].upper(), underline_str)
    if len(sub) > 1:
        return sub[0].upper() + sub[1:]
    return sub
  2. 实现根据字符串导入模块函数, 代码演示:

    • 通过python内置函数__import__函数实现加载类

          def import_object(name):
          """Imports an object by name.
          import_object('x') is equivalent to 'import x'.
          import_object('x.y.z') is equivalent to 'from x.y import z'.
          """
          if not isinstance(name, str):
                  name = name.encode('utf-8')
          if name.count('.') == 0:
                  return __import__(name, None, None)
      
          parts = name.split('.')
          obj = __import__('.'.join(parts[:-1]), None, None, [parts[-1]], 0)
          try:
                  return getattr(obj, parts[-1])
          except AttributeError:
                  raise ImportError("No module named %s" % parts[-1])
    • 通过importlib模块实现
      importlib.import_module(name)

    上面2种方法都可以,github上代码里2种方法都有测试。

  3. 检索resources文件夹,生成路由映射,并导入对应实现类, 代码演示如下:

    def route(route_file_path,
          resources_name="resources",
          route_prefix="",
          existing_route=None):
    
    route_list = []
    
        def get_route_tuple(file_name, route_pre, resource_module_name):
            """
            :param file_name: API file name
            :param route_pre: route prefix
            :param resource_module_name: resource module
            """
            nonlocal route_list
            nonlocal existing_route
            route_endpoint = file_name.split(".py")[0]
            #module = importlib.import_module('{}.{}'.format(
            #    resource_module_name, route_endpoint))
            module = import_object('{}.{}'.format(
                resource_module_name, route_endpoint))
            route_class = underline_to_hump(route_endpoint)
            real_route_endpoint = r'/{}{}'.format(route_pre, route_endpoint)
            if existing_route and isinstance(existing_route, dict):
                if real_route_endpoint in existing_route:
                    real_route_endpoint = existing_route[real_route_endpoint]
            route_list.append((real_route_endpoint, getattr(module, route_class)))
    
        def check_file_right(file_name):
            if file_name.startswith("_"):
                return False
            if not file_name.endswith(".py"):
                return False
            if file_name.startswith("."):
                return False
            return True
    
        def recursive_find_route(route_path, sub_resource, route_pre=""):
            nonlocal route_prefix
            nonlocal resources_name
            file_list = os.listdir(route_path)
            if config.DEBUG:
                print("FileList:", file_list)
            for file_item in file_list:
                if file_item.startswith("_"):
                    continue
                if file_item.startswith("."):
                    continue
                if os.path.isdir(route_path + "/{}".format(file_item)):
                    recursive_find_route(route_path + "/{}".format(file_item), sub_resource + ".{}".format(file_item), "{}{}/".format(route_pre, file_item))
                    continue
                if not check_file_right(file_item):
                    continue
                get_route_tuple(file_item, route_prefix + route_pre, sub_resource)
    
    recursive_find_route(route_file_path, resources_name)
    if config.DEBUG:
        print("RouteList:", route_list)
    
    return route_list
    • get_route_tuple函数作用是通过字符串导入类,并将路由和类以元组的方式添加到数组中。
    • check_file_right函数作用是过滤文件夹中不合法的文件。
    • recursive_find_route函数采用递归查找resources中的文件。
    • existing_route参数是将已经线上存在的路由替换新规则生成的路由,这样旧项目也是可以优化使用这套规则。

3. 应用到项目中

以flask框架为例,其余框架请看github中的代码演示。
app.py 中代码

   app = Flask(__name__)
   api = Api(app)
   # APi route and processing functions
   exist_route = {"/flask/hello_world": "/hello_world"}
   route_path = "./resources"
   route_list = route(
       route_path,
       resources_name="resources",
       route_prefix="flask/",
       existing_route=exist_route)

   for item in route_list:
       api.add_resource(item[1], item[0])

   if __name__ == "__main__":
       app.run(host="0.0.0.0", port=int(parse_args.port), debug=config.DEBUG)

运行app.py之后,路由打印如下:

   RouteList: [
  ('/hello_world', ),
  ('/flask/ab/testab/hello_world_python_test', \
            ), 
  ('/flask/ab/hello_world_python', )
  ]

元组第一个元素则是路由,第二个元素是对应的实现类。


总结:
至此,通过制定一定规则,解放路由管理文件方案完成。 欢迎各位一起讨论其余比较好的方案,更多方案讨论可以关注微信公众号: 天澄的技术笔记
Python Web开发: 教你如何解放路由管理

另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


新闻标题:PythonWeb开发:教你如何解放路由管理-创新互联
本文路径:http://mzwzsj.com/article/ceiooj.html

其他资讯

让你的专属顾问为你服务