Save 37% off PRO during our Black Friday Sale! »

Advanced Flask: Recipes For An All-weather Craft

Advanced Flask: Recipes For An All-weather Craft

Abstract: Flask is favoured for prototyping. It is easy to set up and run. However, choosing Flask as your main 'cheval de bataille', be it as a company or individual, requires solid grounding. Flask lets you choose your own ingredients, which lights up the joy of coding but bites if not being careful. This talk covers the standard techniques not to be missed as well as new audacious ones used to help manage BIG codebases.

F65d4a2815f15b782220132cd4bc5a5e?s=128

Abdur-Rahmaan Janhangeer

October 21, 2021
Tweet

Transcript

  1. Advanced Flask: Recipes For An All-weather Craft

  2. PyCon Sweden

  3. 3

  4. Python Mauritius UserGroup (pymug) More info: mscc.mu/python-mauritius-usergroup-pymug/ pymug.com Why Where

    codes github.com/pymug share events twitter.com/pymugdotcom ping professionals linkedin.com/company/pymug all info pymug.com tell friends by like facebook.com/pymug 4
  5. Abdur-Rahmaan Janhangeer (Just a Python programmer) twitter: @osdotsystem github: github.com/abdur-rahmaanj

    compileralchemy.com 5
  6. FlaskCon organising member + Flask Community Workgroup member 6

  7. Advanced Flask: Recipes For An All-weather Craft 7

  8. The Flask Story 8

  9. Begin new project 9

  10. Code features 10

  11. Deploy 11

  12. Refine Deploy 12

  13. TEST AND PROD ENV DIFFERENT 13

  14. USE CONFIGURATION PROFILES 14

  15. ADD APP FACTORY 15

  16. APP BREAKING 16

  17. WRITE TESTS 17

  18. CODE DISORGANISED 18

  19. ORGANISE CODEBASE 19

  20. TESTS ARE BORING 20

  21. WRITE FIXTURES, WRITE SCHEMAS 21

  22. I HAVE TO START A NEW PROJECT 22

  23. HAVE A TEMPLATE 23

  24. NOW I HAVE TO USE APIS 24

  25. INTEGRATE API-FRAMEWORK 25

  26. pulls some more hair 26

  27. I WANT TO INTEGRATE CELERY 27

  28. INTEGRATE CELERY 28

  29. dev left ... 29

  30. THE NEW INTERN DOES NOT UNDERSTAND ANYTHING 30

  31. WRITE DOCS!!! 31

  32. You need something that flies in all weather 32

  33. The Application Factory 33

  34. def create_app(app_name): app = Flask(app_name) return app 34

  35. Configuration Profiles 35

  36. class Config: TESTING = False class ProductionConfig(Config): FAV_FLOWER = 'rose'

    class DevelopmentConfig(Config): FAV_FLOWER = 'sunflower' class TestingConfig(Config): FAV_FLOWER = 'moonlight petal' TESTING = True 36
  37. from config import ProductionConfig from config import DevelopmentConfig from config

    import TestingConfig profiles = { 'development': DevelopmentConfig(), 'production': ProductionConfig(), 'testing': TestingConfig() } def create_app(profile): app = Flask(__name__) app.config.from_object(profiles[profile]) return app 37
  38. Tests 38

  39. Use Pytest Use class-based testing Define fixtures for common actions

    e.g. logout/login 39
  40. Docs 40

  41. Use Sphinx from the start 41

  42. Separate Initialisations From The Factory 42

  43. Use a file for initialisations Reduces import errors to a

    max 43
  44. app.py init.py 44

  45. init.py db = SQLAlchemy() ma = Marshmallow() login_manager = LoginManager()

    migrate = Migrate() mail = Mail() 45
  46. from init import mail def create_app(...): app = ... mail.init_app(app)

    in other files: from init import db 46
  47. Use modules for everything!!! 47

  48. app.py module1/ module2/ module3/ 48

  49. app.py modules/ module1/ module2/ 49

  50. module1/ templates/ static/ test/ models.py forms.py view.py etc etc 50

  51. Use flask to simplify your life 51

  52. @app.cli.command("jump", short_help="skip something") def jump(): # do something return 0

    # cli flask jump 52
  53. Automate blueprint registration 53

  54. 1. name each blueprint: foldername_blueprint 2. In app.py # pseudocode

    for folder in modules: blueprint = import(f'modules.{folder}.view.{folder}_blueprint') app.register(blueprint) 54
  55. Automate module creation 55

  56. # pseudocode def createmodule(name): mkdir(folder) touch(folder/models.py) touch(folder/) ... # cli

    flask createmodule apple 56
  57. Form help yourself 57

  58. Use flask-wtf Use wtforms-alchemy class ConfForm(ModelForm): class Meta: model =

    Conf 58
  59. Contain static in module, implement collecstatic 59

  60. app.py static/ # served from here in production modules/ m1/

    static/ file.png m2/ static/ file.png collectstatic just collects all assets in all modules and add it under app.py static/ modules/ m1/ file.png m2/ file.png 60
  61. define function serve_asset(module, resource_path) e.g. serve_asset('m1', 'file.png') if mode is

    dev serve from /modules/m1/static/file.png i.e /modules/module_name/m1/static/path/to/file.png if mode is prod serve from /static/modules/m1/file.png (assumes collecstatic run before) i.e /static/modules/module_name/path/to/file.png 61
  62. What for celery? 62

  63. app.py init.py celery_app.py modules/ m1/ task.py 63

  64. init.py celery = Celery( __name__, broker=BaseConfig.CELERY_BROKER_URL, backend=BaseConfig.CELERY_RESULT_BACKEND, ) 64

  65. app.py from init import celery def init_celery(app=None): app = create_app(os.getenv("FLASK_ENV",

    "")) app = app or create_app() celery.conf.update(app.config) class ContextTask(celery.Task): """Make celery tasks work with Flask app context""" def __call__(self, *args, **kwargs): with app.app_context(): return self.run(*args, **kwargs) celery.Task = ContextTask return celery 65
  66. celery_app.py from app import init_celery celery = init_celery() 66

  67. modules/m1/task.py from init import celery @celery.task(name="do something", bind=True) def task_do_something(self):

    67
  68. What for flask-restx? 68

  69. modules/ app.py init.py api_util.py 69

  70. init.py api = Api( version="1.0", title="MVP Data", description="Backend Part", authorizations=authorizations,

    ) 70
  71. api_util.py # from modules.some.api import some_ns from modules.some2.api import some2_ns

    # ns: namespace from init import api_v1 api_v = api_v1 # /api/v1 def add_api(api): api.add_namespace(some_ns, path=api_v + "/someapi") api.add_namespace(some2_ns, path=api_v + "/someapi2") 71
  72. app.py from init import api from api_util import add_api def

    create_app(...): app = ... api.init_app(app) add_api(api) 72
  73. Migrations to the next level 73

  74. # make flask-migrate auto detect models for folder in modules:

    import(f'modules.{folder}.models.py') 74
  75. Modular migration ideas: make flask_migrate or alembic load only specific

    classes 75
  76. Reuse base 76

  77. Use cookiecutter cookiecutter <url> Keep modules and init.py empty 77

  78. The ongoing conclusion: 78

  79. https://github.com/shopyo/shopyo Star it to show support! 79

  80. Helped you? appreciate a mail at: arj.python@gmail.com Really means a

    lot to me!!!!! 80