[
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Lucien Rae\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Flask Cheat Sheet\nA cheat-sheet for creating web apps with the Flask framework using the Python language.\n\n## Contents\n- [Creating a Simple App](#creating-a-simple-app)\n- [Structuring an Application with Blueprints](#structuring-an-application-with-blueprints)\n- [Creating Object-Based Configuration](#creating-object-based-configuration)\n- [Using the Jinja2 Template Engine](#using-the-jinja2-template-engine)\n- [Creating Models with SQLAlchemy](#creating-models-with-sqlalchemy)\n- [Using Database Migrations](#using-database-migrations)\n- [Creating a Login Manager](#creating-a-login-manager)\n- [Connecting to a MySQL database](#connecting-to-a-mysql-database)\n\n## Creating a Simple App\n- Create a module called `app.py`:\n```python\nfrom flask import Flask\n\napp = Flask(__name__)\n\n@app.route('/')\ndef index():\n\treturn 'Hello, World!'\n\nif __name__ == '__main__':\n\tapp.run()\n```\n\n## Structuring an Application with Blueprints\n- Example project tree for a project called `project`:\n```\nrun.py\nproject/\n\t__init__.py\n\tconfig.py\n\tforms.py\n\tmodels.py\n\tadmin/\n\t\t__init__.py\n\t\troutes.py\n\tmain/\n\t\t__init__.py\n\t\troutes.py\n\ttemplates/\n\t\tindex.html\n\tstatic/\n\t\tcss/\n\t\t\tstyle.css\n```\n- In `run.py`:\n```python\nfrom project import app\n\nif __name__=='__main__':\n\tapp.run()\n```\n- In `project/__init__.py`:\n```python\nfrom flask import Flask\nfrom project.main.routes import main\nfrom project.admin.routes import admin\n\napp = Flask(__name__)\n\napp.register_blueprint(main, url_prefix='/')\napp.register_blueprint(admin, url_prefix='/admin')\n```\n- In `project/main/routes.py`:\n```python\nfrom flask import Blueprint\n\nmain = Blueprint('main', __name__)\n\n@main.route('/')\ndef index():\n\treturn \"Hello, World! This is the main page.\"\n```\n- In `project/admin/routes.py`:\n```python\nfrom flask import Blueprint\n\nadmin = Blueprint('admin', __name__)\n\n@main.route('/')\ndef index():\n\treturn \"Hello, World! This is the admin page.\"\n```\n## Creating Object-Based Configuration\n- Create `project/config.py`:\n```python\nclass BaseConfig(object):\n\tSECRET_KEY = os.environ.get('SECRET_KEY') or 'abcdef123456'\n\tDEBUG = False\n\tTESTING = False\n\nclass DevelopmentConfig(BaseConfig):\n\tDEBUG = True\n\tTESTING = True\n\nclass TestingConfig\n\tDEBUG = False\n\tTESTING = True\n```\n- And then in `__init__.py` include:\n```python\nfrom flask import Flask\nfrom threechan import config\n\napp = Flask(__name__)\napp.config.from_object(config.DevelopmentConfig)\n```\n## Using the Jinja2 Template Engine\n- Rendering a template from `main/routes.py`:\n```python\nfrom flask import Blueprint, render_template\n\n@main.route('/')\ndef home():\n\tposts = [\n\t\t{\n\t\t\t\"body\": \"Hello, this is a post\",\n\t\t\t\"timestamp\": \"This is a date and time\",\n\t\t}\n\t]\n\t\n\treturn render_template(\"home.html\", posts=posts)\n```\n- Using Jinja2 inside `templates/home.html`:\n```html\n{% for posts in posts %}\n\t<div>\n\t\t{{ post.body }} <br>\n\t\t{{ post.timestamp }}\n\t</div>\n{% endfor %}\n```\n- Using filters:\n```html\n{{ body|upper }}\n```\n- Creating custom filters:\n```python\n@main.template_filter('trim_upper')\ndef string_trim_upper(value):\n\treturn value.strip().upper()\n``` \n- Using `extends`:\n\nin **index.html**\n```html\n{% extends 'base.html' %}\n\n{% block content %}\n<p>\n\tHello, world!\n</p>\n{% endblock %}\n```\nin **base.html**\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width initial-scale=1\">\n\t</head>\n\t<body>\n\t\t{% blockcontent %}{% endblock %}\n\t</body>\n</html>\n```\n- Using `includes`:\n```html\n{% includes '_post.html' %}\n```\n- Adding a stylesheet from `templates/base.html`:\n```html\n<link rel=\"stylesheet\" href=\"{{ url_for('static', filename='css/style.css') }}\">\n```\n## Creating Models with SQLAlchemy\n- In `project/models.py`:\n```python\nfrom flask_sqlalchemy import SQLAlchemy\n\ndb = SQLAlchemy()\n\nclass Post(db.Model):\n\tid = db.Column(db.Integer, primary_key=True)\n\tbody = db.Column(db.String(256))\n\n\tdef __init__(self, body):\n\t\tself.body = body\n\n\tdef __repr__(self):\n\t\treturn \"<Post({})>\".format(self.id)\n```\n- In `project/__init__.py`\n```python\nfrom project.models improt db\n\napp = Flask(__name__)\napp.config.from_object(config.DevelopmentConfig)\nwith app.app_context():\n\tdb.init_app()\n```\n- In `project/config.py`:\n```python\nimport os\nBASE_DIR = os.path.abspath(os.path.dirname(__name__))\n\nclass BaseConfig(object):\n\t# ...\n\tSQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'data.db'\n\tSQLALCHEMY_TRACK_MODIFICATIONS = False\n```\n- Creating the database and interacting with models and queries inside the shell:\n```bash\n>>> from project import app, db\n>>> from project.models import Post\n>>> app.app_context().push()\n>>> db.create_all()\n>>> p = Post('Hello!')\n>>> db.session.add(p)\n>>> db.session.commit()\n>>> posts = Post.query.all()\n```\n- To operate through `$ flask shell`, include the following in `project/__init__.py`:\n```python\nfrom project.models import db, User, Post\n\n@app.shell_context_processor\ndef make_shell_context():\n\treturn {'app': app, 'db': db, 'User': User, 'Post': Post}\n```\n- For more info on `Flask-SQLAlchemy`: [official flask-sqlalchemy guide](http://flask-sqlalchemy.pocoo.org/2.1/quickstart/).\n- For more info on `contexts`: [official flask-sqlalchemy contexts guide](http://flask-sqlalchemy.pocoo.org/2.3/contexts/)\n\n## Using Database Migrations\n- Add the following to `project/__init__.py`:\n```python\nfrom flask_migrate import Migrate\n\napp = Flask(__name__)\napp.config.from_object)config.DevelopmentConfig)\nmigrate = Migrate(app, db)\n```\n- To initialize the `migrations` folder:\n```bash\n$ flask db init\n```\n- To migrate:\n```\n$ flask db migrate\n```\n- To upgrade:\n```\n$ flask db upgrade\n```\n## Creating a Login Manager\n- In `models.py` include:\n```python\nfrom flask_login import LoginManager, UserMixin\n\nlogin_manager = LoginManager()\n\n@login_manager.user_loader\ndef load_user(user_id):\n\treturn User.get(user_id)\n```\n- in `project/__init__.py` include:\n```python\nfrom project.models import login_manager\n\nwith app.app_context():\n\tlogin_manager.init_app(app)\n```\n## Connecting to a MySQL database\n- Although `SQLite` is fine for a simple development server, the databases of production servers are often better suited to a more full-featured DBMS like `MySQL`.\n  \n- Install `MySQL`:\n```bash\n$ sudo apt-get install mysql-server\n```\n#### If not prompted to enter a password:\n```bash\n$ sudo mysql_secure_installation\n```\n- And then:\n```bash\n$ sudo mysql -u root -p\n```\n```sql\nCREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';\nGRANT ALL PRIVILEGES ON database_name.* TO 'newuser'@'localhost';\n```\n\n#### Access the `MySQL` shell:\n```bash\n$ mysql -u root -p\n```\n*Note:* `root` *of MySQL is not the same as the* `root` of the OS.\n\n- Show databases with:\n```sql\nSHOW DATABASES;\n```\n- Create a database:\n```sql\nCREATE DATABASE database_name;\n```\n- Establish connection with `SQLAlchemy`, install `pymysql`:\n```bash\n$ pip install pymysql\n```\n- And within the config object in `config.py` include:\n```python\nSQLALCHEMY_DATABASE_URI  =  'mysql+pymysql://root:password@localhost/database';\n```\n- For more standard commands: the [Digital Ocean MySQL tutorial](https://www.digitalocean.com/community/tutorials/a-basic-mysql-tutorial) is useful.\n"
  }
]