{"id":18256576,"url":"https://github.com/honmaple/flask-maple","last_synced_at":"2026-03-17T19:43:20.520Z","repository":{"id":57430471,"uuid":"56497787","full_name":"honmaple/flask-maple","owner":"honmaple","description":"flask tips","archived":false,"fork":false,"pushed_at":"2019-05-13T14:44:06.000Z","size":3662,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-09-20T22:45:03.895Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/honmaple.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-18T10:12:14.000Z","updated_at":"2022-10-28T07:59:08.000Z","dependencies_parsed_at":"2022-08-26T05:01:41.211Z","dependency_job_id":null,"html_url":"https://github.com/honmaple/flask-maple","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/honmaple/flask-maple","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/honmaple%2Fflask-maple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/honmaple%2Fflask-maple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/honmaple%2Fflask-maple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/honmaple%2Fflask-maple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/honmaple","download_url":"https://codeload.github.com/honmaple/flask-maple/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/honmaple%2Fflask-maple/sbom","scorecard":{"id":468741,"data":{"date":"2025-08-11","repo":{"name":"github.com/honmaple/flask-maple","commit":"1ba9b301ca2ed70ab05fa6860f01468400a7fa15"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-19T13:13:46.173Z","repository_id":57430471,"created_at":"2025-08-19T13:13:46.173Z","updated_at":"2025-08-19T13:13:46.173Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30629869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-17T17:32:55.572Z","status":"ssl_error","status_checked_at":"2026-03-17T17:32:38.732Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T10:22:38.903Z","updated_at":"2026-03-17T19:43:20.497Z","avatar_url":"https://github.com/honmaple.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"* Flask-Maple\n\n  [[https://pypi.python.org/pypi/Flask-Maple][https://img.shields.io/badge/pypi-v0.5.5-brightgreen.svg]]\n  [[https://pypi.python.org/pypi/Flask-Maple][https://img.shields.io/badge/python-3.4-brightgreen.svg]]\n  [[LICENSE][https://img.shields.io/badge/license-BSD-blue.svg]]\n\n** 安装\n   To install Flask-Maple:\n   #+BEGIN_SRC python\npip install flask-maple\n   #+END_SRC\n\n   Or alternatively, you can download the repository and install manually by doing:\n   #+BEGIN_SRC python\ngit clone git@github.com:honmaple/flask-maple.git\ncd flask-maple\npython setup.py install\n   #+END_SRC\n\n** 用户系统\n   在 *flask_maple/auth/model.py* 中默认实现了 *GroupMixin* 与 *UserMixin*\n   如果要创建 user 表与 group 表,只需要\n   #+BEGIN_SRC python\n     from flask_maple.auth.models import UserMixin, GroupMixin\n\n     class User(db.Model, UserMixin):\n         pass\n\n     class Group(db.Model, GroupMixin):\n         pass\n   #+END_SRC\n   即可\n   \n   *user* 表默认创建以下字段, 可添加更多想要的字段\n   - id\n   - username\n   - password\n   - email\n   - is_superuser\n   - is_confirmed\n   - register_time\n   - last_login\n   - groups\n     \n   *group* 表默认创建以下字段\n   - id\n   - name\n   - users\n   - parent_group\n   - child_groups\n\n** 权限\n*** 使用\n    #+BEGIN_SRC python\n      from flask_maple.permission.models import PermissionMixin\n\n      class Permission(db.Model, PermissionMixin):\n          pass\n    #+END_SRC\n    \n    user 表与 group 表可继承 *flask_maple.permission.models.UserMixin* 与 *flask_maple.permission.models.GroupMixin*\n    或者直接使用 *flask_maple.auth.models.UserMixin* 与 *flask_maple.auth.models.GroupMixin*\n    \n    - 添加权限\n      #+BEGIN_SRC python\n        identity = user # or group\n        identity.add_perm(\n            action,\n            resource,\n            resource_type='endpoint',\n            description=None)\n      #+END_SRC\n      \n    - 删除权限\n      #+BEGIN_SRC python\n        identity.remove_perm(\n            action,\n            resource,\n            resource_type='endpoint')\n      #+END_SRC\n      \n    - 检查权限\n      #+BEGIN_SRC python\n        identity.has_perm(action, resource, resource_type='endpoint', and_=False)\n      #+END_SRC\n       \n*** 权限缓存\n    默认权限会从数据库获取, 如果经常使用，可自行添加缓存, 并在添加删除权限后自行对缓存进行操作\n    #+BEGIN_SRC python\n      class User(db.Model, UserMixin):\n          def perm_cache(self,\n                         action,\n                         resource,\n                         resource_type='endpoint',\n                         and_=False):\n              return\n    #+END_SRC\n    \n** 登录\n   依赖于 *flask-login*, *flask-mail*\n   \n*** 使用\n    #+BEGIN_SRC python\n     from flask_maple import auth\n\n     auth.init_app(app)\n\n     # 或者\n     from flask_maple.auth.views import Auth\n\n     Auth(app)\n    #+END_SRC\n   \n    将会创建 6个 *url*\n\n    - /login\n    - /logout\n    - /register\n    - /forget\n    - /confirm\n    - /confirm/\u003ctoken\u003e\n\n    可以自定义登陆，注册，忘记密码页面，以登陆页面为例 (templates/maple/login.html)\n    #+BEGIN_SRC html\n     {% extends \"base/base.html\" %}\n     {%- block content -%}\n     {% import 'maple/auth.html' as auth %}\n     \u003cdiv class=\"panel panel-primary\"\u003e\n         \u003cdiv class=\"panel-heading\"\u003e\n             \u003ca href=\"{{ url_for('auth.login') }}\" style=\"color:#fff\"\u003e{{ _('Login')}}\u003c/a\u003e\n         \u003c/div\u003e\n         \u003cdiv class=\"panel-body\"\u003e\n             {{ auth.login()}}\n         \u003c/div\u003e\n     \u003c/div\u003e\n     {% endblock %}\n    #+END_SRC\n   \n*** 注意事项\n    登陆与登出默认使用 *user.login(remember)* , *user.logout()*, 如果未使用 *flask_maple/auth/model.py* 中的 *UserMixin*,则需要自己定义\n\n** 验证码\n   使用 *Pillow* 生成验证码\n\n   #+BEGIN_SRC python\n    pip install pillow\n   #+END_SRC\n\n*** 使用\n    #+BEGIN_SRC python\n      from flask_maple import Captcha\n      captcha = Captcha(app)\n\n      # 因为字体可能存在侵权，所以需要指定自己服务器字体, 默认为 /usr/share/fonts/TTF/DejaVuSans.ttf\n      captcha = Captcha(app, font=\"\")\n    #+END_SRC\n    然后访问 [[http://127.0.0.1/captcha][http://127.0.0.1/captcha]]\n\n*** 配置\n    #+BEGIN_SRC python\n    CAPTCHA_URL = \"The captcha url,default 'captcha'\"\n    #+END_SRC\n\n** 错误处理\n   主要是对发生错误时的页面进行定制(403,404,500)\n   #+BEGIN_SRC python\n     from flask_maple import Error\n     error = Error(app)\n   #+END_SRC\n   \n   定制图片源于*flask*官网,侵删\n   \n** 邮箱\n   依赖于 *flask-mail*, 区别使用多线程发送\n\n   #+BEGIN_SRC python\n     from flask_maple.mail import Mail\n\n     mail = Mail(app)\n     mail.send_email(*args, **kwargs)\n   #+END_SRC\n   \n   此外，还有一个 *MailMixin*,实现了邮箱验证需要的密钥,\n   #+BEGIN_SRC python\n     from flask_maple.mail import MailMixin\n\n     class User(db.Model, MailMixin):\n         pass\n\n     print(user.email_token)\n     print(User.check_email_token(token, max_age=259200))\n   #+END_SRC\n** 表单\n** 数据库\n   像 django 一样使用 *flask-sqlalchemy*\n   *djang orm* 与 sqlalchemy 相比,为什么很多人都认为 django orm 更好用,大概就是因为 django orm 更方便\n\n*** 基本查询(已实现)\n    - gt\n    - lt\n    - lte\n    - gte\n    - contains\n    - in\n    - exact\n    - iexact\n    - startswith\n    - istartswith\n    - iendswith\n    - endswith\n    - isnull\n    - range\n    - year\n    - month\n    - day\n\n    示例:\n    #+BEGIN_SRC python\n   Post.query.filter_by(title__contains = 'sql').all()\n   Post.query.exclude_by(title__contains = 'sql').all()\n    #+END_SRC\n\n*** 关系查询\n    #+BEGIN_SRC python\n   Post.query.filter_by(tags__name__contains = 'sql').all()\n    #+END_SRC\n\n*** 其它\n    #+BEGIN_SRC python\n      Post.query.filter_by(tags__name__contains = 'sql').or(Post.id == 1,Post.id == 2).all()\n      Post.query.filter_by(tags__name__contains = 'sql').and(Post.id == 1,Post.id == 2).all()\n      Post.query.filter_by(tags__name__contains = 'sql').exists()\n      Post.query.load_only('title')\n    #+END_SRC\n\n** 序列化\n   把 *sqlalchemy* 对象序列化为 *json*, 使用方法参考于 *django rest framework*\n   \n*** 多个实例\n    #+BEGIN_SRC python\n      from flask_maple.serializer import Serializer\n\n      posts = Post.query.all()\n      serializer = Serializer(posts)\n      data = serializer.data\n    #+END_SRC\n    \n*** 单个实例\n    #+BEGIN_SRC python\n     post = Post.query.first()\n     serializer = Serializer(post)\n     data = serializer.data\n    #+END_SRC\n   \n*** 排除字段\n    #+BEGIN_SRC python\n      serializer = Seralizer(post,exclude=['title'])\n    #+END_SRC\n\n*** 仅包括字段\n    #+BEGIN_SRC python\n      serializer = Seralizer(post,include=['title'])\n    #+END_SRC\n\n*** 关系查询深度\n    #+BEGIN_SRC python\n      serializer = Seralizer(post,depth=3)\n    #+END_SRC\n    depth 默认为*2*\n      \n*** 额外的字段\n    #+BEGIN_SRC python\n     class Post(Model):\n         ......\n         def get_post_count(self):\n             return 11\n\n     serializer = Serializer(post,extra=['get_post_count'])\n    #+END_SRC\n   \n*** 自定义\n    #+BEGIN_SRC python\n    from flask_maple.serializer import Serializer\n\n    class PostSerializer(Serializer):\n        class Meta:\n            include = []\n            depth = 2\n            include = []\n            exclude = []\n            extra = ['count']\n\n    serializer = PostSerializer(post,include=['title'])\n    #+END_SRC\n\n** 中间件\n   参考于 *django* \n   #+BEGIN_SRC python\n     from flask_maple.middleware import Middleware\n\n     app = ...\n     Middleware(app)\n   #+END_SRC\n   \n   中间件写法(以一个简单的性能测试中间件为例)\n   #+BEGIN_SRC python\n     class ProfileMiddleware(object):\n         def preprocess_request(self):\n             pr = cProfile.Profile()\n             pr.enable()\n             request.pr = pr\n\n         def process_response(self, response):\n             pr = request.pr\n             pr.disable()\n             s = StringIO()\n             sortby = 'cumulative'\n             ps = pstats.Stats(pr, stream=s).sort_stats(sortby)\n             ps.print_stats()\n             print(s.getvalue())\n             return response\n   #+END_SRC\n   \n   *重要* ，需要加入中间件配置\n   #+BEGIN_EXAMPLE\n   MIDDLEWARE = [\"path.to.ProfileMiddleware\"]\n   #+END_EXAMPLE\n\n** 日志\n   记录 *info* 和 *error* 两个日志 level, 使用很简单\n   #+BEGIN_SRC python\n     from flask_maple.log import Logging\n\n     app = ...\n     Logging(app)\n   #+END_SRC\n   \n   配置文件\n   #+BEGIN_SRC python\n     LOGGING = {\n         'info': 'logs/info.log',   # 记录 info level 的日志,与配置文件同级下的 logs 目录,可修改\n         'error': 'logs/error.log', # 记录 error level 的日志\n         'send_mail': False,        # 当有错误发生时，是否发送邮件到管理员邮箱\n         'toaddrs': [],             # 管理员邮箱，可为多个\n         'subject': 'Your Application Failed',\n         'formatter': '''\n                 Message type:       %(levelname)s\n                 Location:           %(pathname)s:%(lineno)d\n                 Module:             %(module)s\n                 Function:           %(funcName)s\n                 Time:               %(asctime)s\n\n                 Message:\n\n                 %(message)s\n                 '''\n     }\n   #+END_SRC\n   \n   当*send_mail*为 *True*时, 配置依赖于 *flask_mail*的配置(主要是不想写多份)\n   #+BEGIN_EXAMPLE\n     MAIL_USERNAME\n     MAIL_PASSWORD\n     MAIL_SERVER\n     MAIL_PORT\n     MAIL_DEFAULT_SENDER\n   #+END_EXAMPLE\n** App\n   创建两个常用的 *url*\n\n   - /robots.txt\n   - /favicon.ico\n     \n*** 使用\n    #+BEGIN_SRC python\n      from flask_maple.app import App\n\n      App(app)\n    #+END_SRC\n    \n    此外,因为国际化等原因,可以传递 *flask_maple.json.CustomJSONEncoder* 给 App\n    #+BEGIN_SRC python\n      from flask_maple.app import App\n      from flask_maple.json import CustomJSONEncoder\n\n      App(app, json=CustomJSONEncoder)\n    #+END_SRC\n    \n*** 配置\n    参考于 django,可以懒加载 blueprint\n    #+BEGIN_EXAMPLE\n      INSTALLED_APPS = [\n          \"path.to.blueprint1\",\n          \"path.to.blueprint2\",\n          {\n              \"kwargs\":{},\n              \"blueprint\":{}\n          }\n      ]\n    #+END_EXAMPLE\n** Bootstrap\n   主要是个人经常使用的一些模板,比如 bootstrap 的js,css 文件，分页模板, 上下撑满等\n   并依赖于 *flask-assets* ,对 js,css 文件进行压缩\n\n*** 使用\n    #+BEGIN_SRC python\n      from flask_maple import Bootstrap\n      bootstrap = Bootstrap(\n          app,\n          css=('styles/monokai.css', 'styles/mine.css'),\n          js=('styles/upload.js', 'styles/forums.js', 'styles/following.js',\n              'styles/topic.js'),\n          auth=True)\n    #+END_SRC\n\n    或者\n    #+BEGIN_SRC python\n   bootstrap = Bootstrap()\n   bootstrap.init_app(app)\n    #+END_SRC\n\n*** 模板\n    #+BEGIN_SRC html\n     {% extends 'maple/base.html' %}\n     {% block main -%}\n     \u003cbutton class=\"btn btn-primary\"\u003esubmit\u003c/button\u003e\n     \u003cspan class=\"glyphicon glyphicon-search\" aria-hidden=\"true\"\u003e\u003c/span\u003e\n     {% endblock -%}\n    #+END_SRC\n\n*** 配置\n    #+BEGIN_SRC python\n    AUTHOR_NAME = \"This will show you name at html footer\"\n    #+END_SRC\n\n** Redis\n   默认会加载 *rediscluster.StrictRedisCluster* ,如果 rediscluster 未安装则加载 *redis.StrictRedis*\n   \n*** 使用\n    #+BEGIN_SRC python\n     from flask_maple.redis import Redis\n\n     redis = Redis(app)\n\n     # 像平时使用 redispy 一样使用\n     print(redis.get(...))\n    #+END_SRC\n   \n*** 配置\n    #+BEGIN_EXAMPLE\n    REDSI = {...}\n    #+END_EXAMPLE\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhonmaple%2Fflask-maple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhonmaple%2Fflask-maple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhonmaple%2Fflask-maple/lists"}