Files
black-dashboard-flask/docs/1.0/getting-started/getting-started-flask.html
2020-08-21 17:55:22 +03:00

1593 lines
59 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="apple-touch-icon" sizes="76x76" href="../../../assets/img/dashboard/free/apple-icon.png">
<link rel="icon" type="image/png" href="../../../assets/img/dashboard/free/favicon.png">
<title>
Black Dashboard Flask by Creative Tim
</title>
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<link href="https://use.fontawesome.com/releases/v5.0.6/css/all.css" rel="stylesheet">
<!-- Nucleo Icons -->
<link href="../../../assets/css/nucleo-icons.css" rel="stylesheet" />
<!-- CSS Files -->
<link href="../../../assets/css/dashboard-free.css?v=1.0.0" rel="stylesheet" />
<!-- Documentation extras -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css" />
<link rel="stylesheet" href="../../../assets/demo/docs.min.css">
<style>
.navbar-absolute-logo{
padding-left: 45px;
}
.navbar-absolute-logo img{
position: absolute;
left: 15px;
margin-top: -6px;
}
body{
background: white;
}
</style>
<!-- CSS Just for demo purpose, don't include it in your project -->
<link href="../../../assets/demo/dashboard/free/demo.css" rel="stylesheet" />
</head>
<body class="bd-docs" data-spy="scroll" data-target=".bd-sidenav-active">
<a id="skippy" class="sr-only sr-only-focusable" href="#content">
<div class="container">
<span class="skiplink-text">Skip to main content</span>
</div>
</a>
<header class="navbar navbar-expand bg-primary flex-column flex-md-row bd-navbar">
<a class="navbar-brand mr-0 mr-md-2 navbar-absolute-logo" href="https://www.creative-tim.com/product/black-dashboard-flask" target="_blank">
Black Dashboard Flask
</a>
<ul class="navbar-nav flex-row d-none d-md-flex">
<li class="nav-item">
<a class="nav-link p-2" href="#version">
1.0.0
</a>
</li>
<!-- <li class="nav-item dropdown">
<a class="nav-item nav-link dropdown-toggle mr-md-2" href="#" id="bd-versions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
v2.0.0
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="bd-versions">
<a class="dropdown-item active" href="/docs/1.0/">BS4 - 1.0.0</a>
<a class="dropdown-item" href="">BS3 - 1.2.1</a>
</div>
</li> -->
<li class="nav-item">
<a class="nav-link p-2" href="https://github.com/creativetimofficial/black-dashboard-flask" target="_blank" rel="noopener" aria-label="GitHub">
<svg class="navbar-nav-svg" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"/></svg>
</a>
</li>
<li class="nav-item">
<a class="nav-link p-2" href="https://twitter.com/CreativeTim" target="_blank" rel="noopener" aria-label="Twitter">
<svg class="navbar-nav-svg" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 416.32" focusable="false"><title>Twitter</title><path d="M160.83 416.32c193.2 0 298.92-160.22 298.92-298.92 0-4.51 0-9-.2-13.52A214 214 0 0 0 512 49.38a212.93 212.93 0 0 1-60.44 16.6 105.7 105.7 0 0 0 46.3-58.19 209 209 0 0 1-66.79 25.37 105.09 105.09 0 0 0-181.73 71.91 116.12 116.12 0 0 0 2.66 24c-87.28-4.3-164.73-46.3-216.56-109.82A105.48 105.48 0 0 0 68 159.6a106.27 106.27 0 0 1-47.53-13.11v1.43a105.28 105.28 0 0 0 84.21 103.06 105.67 105.67 0 0 1-47.33 1.84 105.06 105.06 0 0 0 98.14 72.94A210.72 210.72 0 0 1 25 370.84a202.17 202.17 0 0 1-25-1.43 298.85 298.85 0 0 0 160.83 46.92" fill="currentColor"/></svg>
</a>
</li>
</ul>
<div class="navbar-nav-scroll ml-md-auto ">
<ul class="navbar-nav bd-navbar-nav flex-row">
<li class="nav-item">
<a target="_blank" href="javascript:void(0)" rel="nofollow" class="btn btn-round btn-default disabled"><i class="tim-icons icon-send mr-2"></i>Upgrade to PRO</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="../../../docs/1.0/getting-started/introduction.html"><i class="tim-icons icon-app"></i> Documentation</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://www.creative-tim.com/live/black-dashboard-flask"><i class="tim-icons icon-tv-2"></i> Live Preview</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/creativetimofficial/black-dashboard-flask" target="_blank" rel="noopener"><i class="tim-icons icon-shape-star"></i> Help with a star</a>
</li>
<li class="nav-item">
<a class="nav-link" href="" target="_blank" rel="noopener"></a>
</li>
<li class="nav-item">
<a class="nav-link" href="" target="_blank" rel="noopener"></a>
</li>
</ul>
</div>
<a href="https://github.com/creativetimofficial/black-dashboard-flask" class="github-corner" aria-label="View source on Github"><svg width="60" height="60" viewBox="0 0 250 250" style="fill:#fff; color:#9c27b0; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
<!-- <a class="btn btn-white d-none d-lg-inline-block" href="">Download</a> -->
</header>
<div class="container-fluid">
<div class="row flex-xl-nowrap">
<div class="col-12 col-md-3 col-xl-2 bd-sidebar">
<nav class="collapse bd-links" id="bd-docs-nav">
<div class="bd-toc-item active">
<a class="bd-toc-link" href="#docs">
Getting started
</a>
<ul class="nav bd-sidenav">
<li class="active bd-sidenav-active">
<a href="../../../docs/1.0/getting-started/getting-started-flask.html">
Getting Started Flask
</a>
</li>
<li class="">
<a href="../../../docs/1.0/getting-started/license.html">
License
</a>
</li>
</ul>
</div>
<div class="bd-toc-item active">
<a class="bd-toc-link" href="#docs">
Foundation
</a>
<ul class="nav bd-sidenav">
<li class="">
<a href="../../../docs/1.0/foundation/colors.html">
Colors
</a>
</li>
</ul>
</div>
<div class="bd-toc-item active">
<a class="bd-toc-link" href="#docs">
Components
</a>
<ul class="nav bd-sidenav">
<li class="">
<a href="../../../docs/1.0/components/alerts.html">
Alerts
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/badge.html">
Badge
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/breadcrumb.html">
Breadcrumb
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/buttons.html">
Buttons
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/card.html">
Card
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/collapse.html">
Collapse
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/dropdowns.html">
Dropdowns
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/forms.html">
Forms
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/google-maps.html">
Google Maps
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/modal.html">
Modal
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/navs.html">
Navs
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/navbar.html">
Navbar
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/nucleo-icons.html">
Nucleo Icons
</a>
</li>
<li class="">
<a href="../../../docs/1.0/components/tables.html">
Tables
</a>
</li>
</ul>
</div>
<div class="bd-toc-item active">
<a class="bd-toc-link" href="#docs">
Plugins
</a>
<ul class="nav bd-sidenav">
<li class="">
<a href="../../../docs/1.0/plugins/perfect-scrollbar.html">
Perfect Scrollbar
</a>
</li>
<li class="">
<a href="../../../docs/1.0/plugins/chart-js.html">
Chart.js
</a>
</li>
</ul>
</div>
</nav>
</div>
<div class="d-none d-xl-block col-xl-2 bd-toc">
<ul class="section-nav">
<li class="toc-entry toc-h1"><a href="#black-dashboard-flask">Black Dashboard Flask</a>
<ul>
<li class="toc-entry toc-h2"><a href="#what-is-flask">What is Flask</a></li>
<li class="toc-entry toc-h2"><a href="#environment">Environment</a></li>
<li class="toc-entry toc-h2"><a href="#build-the-app">Build the app</a></li>
<li class="toc-entry toc-h2"><a href="#app-codebase-simplified">App Codebase (simplified)</a></li>
<li class="toc-entry toc-h2"><a href="#the-bootstrap-flow">The bootstrap flow</a></li>
<li class="toc-entry toc-h2"><a href="#app-codebase">App Codebase</a></li>
<li class="toc-entry toc-h2"><a href="#app-configuration">App Configuration</a></li>
<li class="toc-entry toc-h2"><a href="#app-tables">App Tables</a></li>
<li class="toc-entry toc-h2"><a href="#app-forms">App Forms</a></li>
<li class="toc-entry toc-h2"><a href="#app-routing">App Routing</a></li>
<li class="toc-entry toc-h2"><a href="#pages--assets">Pages & Assets</a></li>
<li class="toc-entry toc-h2"><a href="#data-structures">Data Structures</a>
<ul>
<li class="toc-entry toc-h3"><a href="#current_user-object">current_user object</a></li>
</ul>
</li>
<li class="toc-entry toc-h2"><a href="#flask-resources">Flask resources</a></li>
</ul>
</li>
</ul>
</div>
<main class="col-12 col-md-9 col-xl-8 py-md-3 pl-md-5 bd-content" role="main">
<h1 class="bd-title" id="content">Black Dashboard Flask</h1>
<p class="bd-lead"></p>
<h1 id="black-dashboard-flask"><a href="https://www.creative-tim.com/product/black-dashboard-flask">Black Dashboard Flask</a></h1>
<p>Black Dashboard Black is a free Bootstrap 4 Admin Template for Django - Features:</p>
<ul>
<li>Design - Black Dashboard (Free version)</li>
<li>UI-Ready, Django Native templating</li>
<li><a href="https://www.sqlite.org/">SQLite</a> database, Native Django ORM</li>
<li>Session-Based auth flow (login, register)</li>
<li>Deployment scripts: <a href="https://www.docker.com/">Docker</a>, <a href="https://gunicorn.org/">Gunicorn</a>/<a href="https://www.nginx.com/">Nginx</a> stack</li>
</ul>
<blockquote>
<p><strong>Links</strong></p>
</blockquote>
<ul>
<li><a href="https://www.creative-tim.com/product/black-dashboard-flask">Black Dashboard Flask</a> - product page</li>
<li><a href="https://www.creative-tim.com/live/black-dashboard-flask">Black Dashboard Flask Demo</a> - LIVE App, default login credentials ** <em>test / pass</em> **</li>
<li><a href="https://github.com/creativetimofficial/black-dashboard-flask/">Black Dashboard Flask Sources</a> - MIT License, released on Github</li>
<li>Tutorials
<ul>
<li><a href="./setup-centos-for-development.html">Set up <code class="highlighter-rouge">CentOS</code> for development</a></li>
<li><a href="./setup-ubuntu-for-development.html">Set up <code class="highlighter-rouge">Ubuntu</code> for development</a></li>
<li><a href="./setup-windows-for-development.html">Set up <code class="highlighter-rouge">Windows</code> for development</a></li>
<li><a href="./flask-deploy-on-heroku.html">Flask - Deploy on HEROKU</a></li>
</ul>
</li>
</ul>
<p><br /></p>
<p><img src="https://raw.githubusercontent.com/app-generator/black-dashboard-flask-demo/master/media/black-dashboard-flask-screen.png" alt="Black Dashboard Flask - Free Django template" /></p>
<p><br /></p>
<h2 id="what-is-flask">What is <a href="https://palletsprojects.com/p/flask/">Flask</a></h2>
<hr />
<p>Flask is a lightweight <a href="/what-is/wsgi/">WSGI</a> web application framework. It is designed to make getting started quick and easy, with the ability to scale up to complex applications.
Classified as a microframework, Flask is written in Python and it does not require particular tools or libraries. It has no database abstraction layer, form validation, or any other components where pre-existing third-party libraries provide common functions.</p>
<blockquote>
<p><strong>Flask Links</strong></p>
</blockquote>
<ul>
<li><a href="https://palletsprojects.com/p/flask/">Flask</a> - the official website</li>
<li><a href="https://flask.palletsprojects.com/">Flask Documentation</a></li>
</ul>
<p><br /></p>
<h2 id="environment">Environment</h2>
<hr />
<p>To use the stater, <a href="https://www.python.org/">Python3</a> should be installed properly in the workstation. If you are not sure if Python is properly installed, please open a terminal and type <code class="highlighter-rouge">python --version</code>. The full-list with dependencies and tools required to build the app:</p>
<ul>
<li><a href="https://www.python.org/">Python3</a> - the programming language used to code the app</li>
<li><a href="https://git-scm.com/">GIT</a> - used to clone the source code from the Github repository</li>
<li>Basic development tools (g++ compiler, python development libraries ..etc) used by Python to compile the app dependencies in your environment.</li>
</ul>
<p><br /></p>
<blockquote>
<p>Check <a href="https://www.python.org/">Python</a> version (using the terminal)</p>
</blockquote>
<div class="language-bash highlighter-rouge">
<div class="highlight">
<pre class="highlight">
<code>
<span class="nv">$ </span><span class="c"># Check Python version</span>
<span class="nv">$ </span>python <span class="nt">--version</span>
Python 3.7.2 <span class="c"># &lt;--- All good</span>
</code>
</pre>
</div>
</div>
<p><br /></p>
<blockquote>
<p>Check <a href="https://git-scm.com/">GIT</a> command tool (using the terminal)</p>
</blockquote>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="c"># Check git</span>
<span class="nv">$ </span>git <span class="nt">--version</span>
<span class="nv">$ </span>git version 2.10.1.windows.1 <span class="c"># &lt;--- All good</span>
</code></pre></div></div>
<p><br /></p>
<p>For more information on how to set up your environment please access the resources listed below. In case weve missed something, contact us on Discord.</p>
<ul>
<li><a href="./setup-centos-for-development.md">Setup CentOS for development</a></li>
<li><a href="./setup-ubuntu-for-development.md">Setup Ubuntu for development</a></li>
<li><a href="./setup-windows-for-development.md">Setup Windows for development</a></li>
</ul>
<p><br /></p>
<h2 id="build-the-app">Build the app</h2>
<hr />
<p>To built and start the app locally, follow the steps:</p>
<blockquote>
<p><strong>Get the source code</strong></p>
</blockquote>
<ul>
<li>Download the ZIP from Github Repository</li>
<li>Using GIT tool in the terminal to clone the source code</li>
</ul>
<blockquote>
<p><strong>Change the current directory</strong> to <code class="highlighter-rouge">source code</code> directory</p>
</blockquote>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="c"># Make sure you are running the commands INSIDE source code directory</span>
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Create and activate a Virtualenv (Unix based systems)</span>
<span class="nv">$ </span>virtualenv <span class="nb">env</span>
<span class="nv">$ </span><span class="nb">source env</span>/bin/activate
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Create and activate a Virtualenv (Windows based systems)</span>
<span class="nv">$ </span><span class="c"># virtualenv env</span>
<span class="nv">$ </span><span class="c"># .\env\Scripts\activate</span>
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Install requirements</span>
<span class="nv">$ </span>pip3 <span class="nb">install</span> <span class="nt">-r</span> requirements.txt
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Set the FLASK_APP environment variable</span>
<span class="nv">$ </span><span class="o">(</span>Unix/Mac<span class="o">)</span> <span class="nb">export </span><span class="nv">FLASK_APP</span><span class="o">=</span>run.py
<span class="nv">$ </span><span class="o">(</span>Windows<span class="o">)</span> <span class="nb">set </span><span class="nv">FLASK_APP</span><span class="o">=</span>run.py
<span class="nv">$ </span><span class="o">(</span>Powershell<span class="o">)</span> <span class="nv">$env</span>:FLASK_APP <span class="o">=</span> <span class="s2">".</span><span class="se">\r</span><span class="s2">un.py"</span>
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Set up the DEBUG environment</span>
<span class="nv">$ </span><span class="c"># (Unix/Mac) export FLASK_ENV=development</span>
<span class="nv">$ </span><span class="c"># (Windows) set FLASK_ENV=development</span>
<span class="nv">$ </span><span class="c"># (Powershell) $env:FLASK_ENV = "development"</span>
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Run the application</span>
<span class="nv">$ </span><span class="c"># --host=0.0.0.0 - expose the app on all network interfaces (default 127.0.0.1)</span>
<span class="nv">$ </span><span class="c"># --port=5000 - specify the app port (default 5000) </span>
<span class="nv">$ </span>flask run <span class="nt">--host</span><span class="o">=</span>0.0.0.0 <span class="nt">--port</span><span class="o">=</span>5000
<span class="err">$</span>
<span class="nv">$ </span><span class="c"># Access the app in browser: http://127.0.0.1:5000/</span>
</code></pre></div></div>
<p>At this point, we can visit the app in the browser <strong><code class="highlighter-rouge">http://127.0.0.1:5000/</code></strong>.
By default, the app will redirect guest users to the login page. To access the private pages:</p>
<ul>
<li>Create a new user using the <strong>registration page</strong></li>
<li>Authenticate using the <strong>login page</strong></li>
</ul>
<p><br /></p>
<h2 id="app-codebase-simplified">App Codebase (simplified)</h2>
<hr />
<p>Starter uses a simple codebase (no Blueprints) with a structure presented bellow:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt; PROJECT ROOT <span class="o">&gt;</span>
|
|-- app/ <span class="c"># Implements app logic</span>
| |-- base/ <span class="c"># Base Blueprint - handles the authentication</span>
| |-- home/ <span class="c"># Home Blueprint - serve UI Kit pages</span>
| |
| __init__.py <span class="c"># Initialize the app</span>
|
|-- requirements.txt <span class="c"># Development modules - SQLite storage</span>
|-- requirements-mysql.txt <span class="c"># Production modules - Mysql DMBS</span>
|-- requirements-pqsql.txt <span class="c"># Production modules - PostgreSql DMBS</span>
|
|-- .env <span class="c"># Inject Configuration via Environment</span>
|-- config.py <span class="c"># Set up the app</span>
|-- run.py <span class="c"># Start the app - WSGI gateway</span>
|
|-- <span class="k">************************************************************************</span>
</code></pre></div></div>
<p><br /></p>
<h2 id="the-bootstrap-flow">The bootstrap flow</h2>
<hr />
<ul>
<li><code class="highlighter-rouge">run.py</code> loads the <code class="highlighter-rouge">.env</code> file</li>
<li>Initialize the app using the specified profile: <em>Debug</em> or <em>Production</em>
<ul>
<li>If env.DEBUG is set to <em>True</em> the SQLite storage is used</li>
<li>If env.DEBUG is set to <em>False</em> the specified DB driver is used (MySql, PostgreSQL)</li>
</ul>
</li>
<li>Call the app factory method <code class="highlighter-rouge">create_app</code> defined in app/<strong>init</strong>.py</li>
<li>Redirect the guest users to Login page</li>
<li>Unlock the pages served by <em>home</em> blueprint for authenticated users</li>
</ul>
<p><br /></p>
<blockquote>
<p><strong><code class="highlighter-rouge">.env</code></strong> (saved in the root of the project)</p>
</blockquote>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># File: `.env`</span>
<span class="nv">DEBUG</span><span class="o">=</span>True <span class="c"># Enable/Disable the development environment</span>
<span class="nv">SECRET_KEY</span><span class="o">=</span>S3cr3t_Key <span class="c"># The Key used by Flask to encrypt session information</span>
<span class="c"># Database production settings (If DEBUG=False)</span>
<span class="nv">DB_ENGINE</span><span class="o">=</span>postgresql <span class="c"># DBMS</span>
<span class="nv">DB_NAME</span><span class="o">=</span>appseed-flask <span class="c"># Database Name</span>
<span class="nv">DB_HOST</span><span class="o">=</span>localhost <span class="c"># Database Host</span>
<span class="nv">DB_PORT</span><span class="o">=</span>5432 <span class="c"># Database Port</span>
<span class="nv">DB_USERNAME</span><span class="o">=</span>appseed <span class="c"># DB Username</span>
<span class="nv">DB_PASS</span><span class="o">=</span>pass <span class="c"># DB Password</span>
</code></pre></div></div>
<p><br /></p>
<blockquote>
<p><strong><code class="highlighter-rouge">run.py</code></strong> (simplified version)</p>
</blockquote>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: run.py
</span>
<span class="n">DEBUG</span> <span class="o">=</span> <span class="n">config</span><span class="p">(</span><span class="s">'DEBUG'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># Create the WSGI app, using the app factory pattern
</span><span class="n">app</span> <span class="o">=</span> <span class="n">create_app</span><span class="p">(</span> <span class="n">app_config</span> <span class="p">)</span>
<span class="c1"># Migrate automaticaly the app using Flask Migrate library
</span><span class="n">Migrate</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">db</span><span class="p">)</span>
</code></pre></div></div>
<p><br /></p>
<blockquote>
<p><strong><code class="highlighter-rouge">app/__init__.py</code></strong> (simplified version)</p>
</blockquote>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: app/__init__.py
</span>
<span class="n">db</span> <span class="o">=</span> <span class="n">SQLAlchemy</span><span class="p">()</span> <span class="c1"># Invoke SQLAlchemy
</span><span class="n">login_manager</span> <span class="o">=</span> <span class="n">LoginManager</span><span class="p">()</span> <span class="c1"># Invoke Login Manager
</span>
<span class="k">def</span> <span class="nf">register_extensions</span><span class="p">(</span><span class="n">app</span><span class="p">):</span>
<span class="n">db</span><span class="p">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> <span class="c1"># Inject SQLAlchemy magic
</span> <span class="n">login_manager</span><span class="p">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> <span class="c1"># Add Login Manager to the app
</span>
<span class="c1"># Register app blueprints: `base`, `home`
</span><span class="k">def</span> <span class="nf">register_blueprints</span><span class="p">(</span><span class="n">app</span><span class="p">):</span>
<span class="k">for</span> <span class="n">module_name</span> <span class="ow">in</span> <span class="p">(</span><span class="s">'base'</span><span class="p">,</span> <span class="s">'home'</span><span class="p">):</span>
<span class="n">module</span> <span class="o">=</span> <span class="n">import_module</span><span class="p">(</span><span class="s">'app.{}.routes'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">module_name</span><span class="p">))</span>
<span class="n">app</span><span class="p">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">module</span><span class="p">.</span><span class="n">blueprint</span><span class="p">)</span>
<span class="c1"># Create the tables (automaticaly)
</span><span class="k">def</span> <span class="nf">configure_database</span><span class="p">(</span><span class="n">app</span><span class="p">):</span>
<span class="o">@</span><span class="n">app</span><span class="p">.</span><span class="n">before_first_request</span>
<span class="k">def</span> <span class="nf">initialize_database</span><span class="p">():</span>
<span class="n">db</span><span class="p">.</span><span class="n">create_all</span><span class="p">()</span>
<span class="c1"># Create the WSGI app using the factory pattern
</span><span class="k">def</span> <span class="nf">create_app</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">,</span> <span class="n">static_folder</span><span class="o">=</span><span class="s">'base/static'</span><span class="p">)</span>
<span class="n">app</span><span class="p">.</span><span class="n">config</span><span class="p">.</span><span class="n">from_object</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
<span class="n">register_extensions</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="n">register_blueprints</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="n">configure_database</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="k">return</span> <span class="n">app</span>
</code></pre></div></div>
<p><br /></p>
<p>The <strong><code class="highlighter-rouge">app/__init__.py</code></strong> constructs the app by putting together a short-list of things:</p>
<ul>
<li>Invoke SQLAlchemy</li>
<li>Invoke and inject the <code class="highlighter-rouge">Login Manager</code> into the app</li>
<li>Load the configuration from <code class="highlighter-rouge">config.py</code> file</li>
<li>Register the app blueprints</li>
<li>Check if the database tables are created</li>
<li>return the WSGI app</li>
</ul>
<p><br /></p>
<h2 id="app-codebase">App Codebase</h2>
<hr />
<p>The starter defines two blueprints:</p>
<ul>
<li><em>Base</em> blueprint - handles the authentication (routes and forms) and assets management</li>
<li><em>Home</em> blueprint - serve HTML pages for authenticated users</li>
</ul>
<p><br /></p>
<blockquote>
<p><strong>App / Base Blueprint</strong> structure</p>
</blockquote>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt; PROJECT ROOT <span class="o">&gt;</span>
|
|-- app/
| |-- home/ <span class="c"># Home Blueprint - serve app pages (private area)</span>
| |-- base/ <span class="c"># Base Blueprint - handles the authentication</span>
| |-- static/
| | |-- &lt;css, JS, images&gt; <span class="c"># CSS files, Javascripts files</span>
| |
| |-- templates/ <span class="c"># Templates used to render pages</span>
| |
| |-- includes/ <span class="c">#</span>
| | |-- navigation.html <span class="c"># Top menu component</span>
| | |-- sidebar.html <span class="c"># Sidebar component</span>
| | |-- footer.html <span class="c"># App Footer</span>
| | |-- scripts.html <span class="c"># Scripts common to all pages</span>
| |
| |-- layouts/ <span class="c"># Master pages</span>
| | |-- base-fullscreen.html <span class="c"># Used by Authentication pages</span>
| | |-- base.html <span class="c"># Used by common pages</span>
| |
| |-- accounts/ <span class="c"># Authentication pages</span>
| |-- login.html <span class="c"># Login page</span>
| |-- register.html <span class="c"># Registration page</span>
|
|-- requirements.txt <span class="c"># Development modules - SQLite storage</span>
|-- requirements-mysql.txt <span class="c"># Production modules - Mysql DMBS</span>
|-- requirements-pqsql.txt <span class="c"># Production modules - PostgreSql DMBS</span>
|
|-- .env <span class="c"># Inject Configuration via Environment</span>
|-- config.py <span class="c"># Set up the app</span>
|-- run.py <span class="c"># Start the app - WSGI gateway</span>
|
|-- <span class="k">************************************************************************</span>
</code></pre></div></div>
<p><br /></p>
<blockquote>
<p><strong>App / Home Blueprint</strong> structure</p>
</blockquote>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt; PROJECT ROOT <span class="o">&gt;</span>
|
|-- app/
| |-- base/ <span class="c"># Base Blueprint - handles the authentication</span>
| |-- home/ <span class="c"># Home Blueprint - serve app pages (private area)</span>
| |
| |-- templates/ <span class="c"># UI Kit Pages</span>
| |
| |-- index.html <span class="c"># Default page</span>
| |-- page-404.html <span class="c"># Error 404 - mandatory page</span>
| |-- page-500.html <span class="c"># Error 500 - mandatory page</span>
| |-- page-403.html <span class="c"># Error 403 - mandatory page</span>
| |-- <span class="k">*</span>.html <span class="c"># All other HTML pages</span>
|
|-- requirements.txt <span class="c"># Development modules - SQLite storage</span>
|-- requirements-mysql.txt <span class="c"># Production modules - Mysql DMBS</span>
|-- requirements-pqsql.txt <span class="c"># Production modules - PostgreSql DMBS</span>
|
|-- .env <span class="c"># Inject Configuration via Environment</span>
|-- config.py <span class="c"># Set up the app</span>
|-- run.py <span class="c"># Start the app - WSGI gateway</span>
|
|-- <span class="k">************************************************************************</span>
</code></pre></div></div>
<p><br /></p>
<h2 id="app-configuration">App Configuration</h2>
<hr />
<p>The configuration file <strong><code class="highlighter-rouge">config.py</code></strong> (in the root of the project) define a dual configuration controlled via the <code class="highlighter-rouge">.env</code> file ( <code class="highlighter-rouge">DEBUG</code> variable)</p>
<blockquote>
<p><strong>DebugConfig</strong> - default configuration used for development</p>
</blockquote>
<p>This configuration becomes active if <code class="highlighter-rouge">.env</code> file has the <code class="highlighter-rouge">DEBUG</code> file set to <em>True</em></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Development/Debug configuration
</span>
<span class="c1"># Set up the App SECRET_KEY
</span><span class="n">SECRET_KEY</span> <span class="o">=</span> <span class="n">config</span><span class="p">(</span><span class="s">'SECRET_KEY'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">'S#perS3crEt_007'</span><span class="p">)</span>
<span class="c1"># This will create a file in &lt;app&gt; FOLDER
</span><span class="n">SQLALCHEMY_DATABASE_URI</span> <span class="o">=</span> <span class="s">'sqlite:///'</span> <span class="o">+</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">basedir</span><span class="p">,</span> <span class="s">'db.sqlite3'</span><span class="p">)</span>
<span class="n">SQLALCHEMY_TRACK_MODIFICATIONS</span> <span class="o">=</span> <span class="bp">False</span>
</code></pre></div></div>
<p>During the first request, the SQLite database and tables are automatically created in the root in the project.</p>
<blockquote>
<p><em>Hint</em>: to visualize the SQLite database content an external tool should be installed: <a href="https://sqlitebrowser.org/">DB Browser for SQLite</a> it might be a good choice.</p>
</blockquote>
<p><br /></p>
<blockquote>
<p><strong>ProductionConfig</strong> - production configuration</p>
</blockquote>
<p>This configuration becomes active if <code class="highlighter-rouge">.env</code> file has the <code class="highlighter-rouge">DEBUG</code> file set to <em>False</em></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Production configuration
</span>
<span class="n">SESSION_COOKIE_HTTPONLY</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">REMEMBER_COOKIE_HTTPONLY</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">REMEMBER_COOKIE_DURATION</span> <span class="o">=</span> <span class="mi">3600</span>
<span class="c1"># PostgreSQL database
</span><span class="n">SQLALCHEMY_DATABASE_URI</span> <span class="o">=</span> <span class="s">'{}://{}:{}@{}:{}/{}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span>
<span class="n">config</span><span class="p">(</span> <span class="s">'DB_ENGINE'</span> <span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">'postgresql'</span> <span class="p">),</span>
<span class="n">config</span><span class="p">(</span> <span class="s">'DB_USERNAME'</span> <span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">'appseed'</span> <span class="p">),</span>
<span class="n">config</span><span class="p">(</span> <span class="s">'DB_PASS'</span> <span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">'pass'</span> <span class="p">),</span>
<span class="n">config</span><span class="p">(</span> <span class="s">'DB_HOST'</span> <span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">'localhost'</span> <span class="p">),</span>
<span class="n">config</span><span class="p">(</span> <span class="s">'DB_PORT'</span> <span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">5432</span> <span class="p">),</span>
<span class="n">config</span><span class="p">(</span> <span class="s">'DB_NAME'</span> <span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">'appseed-flask'</span> <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>
<p>In this configuration profile, the database defaults to a PostgreSQL DBMS. Make sure the <code class="highlighter-rouge">.env</code> has the right credentials to access the database.</p>
<p><br /></p>
<h2 id="app-tables">App Tables</h2>
<hr />
<p>The file <strong><code class="highlighter-rouge">app/base/models.py</code></strong> (Base Blueprint) defines the table(s) used by the application. Being a simple starter, by default the following tabes are defined:</p>
<ul>
<li>Table #1 - <strong>User</strong> with fields:
<ul>
<li>Id - Primary key, unique</li>
<li>user - Store the username</li>
<li>email - The email address</li>
<li>password - Hashed password</li>
</ul>
</li>
</ul>
<p><br /></p>
<h2 id="app-forms">App Forms</h2>
<hr />
<p>The file <strong><code class="highlighter-rouge">app/base/forms.py</code></strong> (Base Blueprint) defines the table(s) used by the application. Being a simple starter, by default the following forms are defined:</p>
<ul>
<li>Form #1 - <strong>LoginForm</strong> with fields:
<ul>
<li>username</li>
<li>password</li>
</ul>
</li>
</ul>
<p><br /></p>
<ul>
<li>Form #2 - <strong>RegisterForm</strong> with fields:
<ul>
<li>username - used to authenticate</li>
<li>email - email address</li>
<li>password - used to authenticate</li>
</ul>
</li>
</ul>
<p><br /></p>
<h2 id="app-routing">App Routing</h2>
<hr />
<p>The routing rules are defined by <em>Base</em> and <em>Home</em> blueprints as specified below. This is the public zone of the app.</p>
<blockquote>
<p><strong>Base Blueprint</strong> - routing file <code class="highlighter-rouge">app/base/routes.py</code></p>
</blockquote>
<ul>
<li><code class="highlighter-rouge">/login</code> route is resolved by <code class="highlighter-rouge">login()</code> method</li>
<li><code class="highlighter-rouge">/register</code> route is resolved by <code class="highlighter-rouge">register()</code> method</li>
<li><code class="highlighter-rouge">/logout</code> route calls the <code class="highlighter-rouge">logout_user()</code> defined in <a href="https://flask-login.readthedocs.io/en/latest/">flask_login</a></li>
</ul>
<p><em>Registered ERROR handlers</em></p>
<ul>
<li>404 Error - Page not found</li>
<li>403 Error - Access Forbidden</li>
<li>500 Error - Internal Error</li>
</ul>
<p><br /></p>
<blockquote>
<p><strong>Home Blueprint</strong> - routing file <code class="highlighter-rouge">app/home/routes.py</code></p>
</blockquote>
<p>This blueprint will serve requested pages from <code class="highlighter-rouge">app/home/templates</code> directory to authenticated users.
The authentication status is checked by <code class="highlighter-rouge">@login_required</code> decorator.</p>
<ul>
<li><code class="highlighter-rouge">/&lt;template&gt;</code> route resolved by <code class="highlighter-rouge">route_template()</code>.
<ul>
<li>If a requested page is not found a default 404 page is returned to the user</li>
</ul>
</li>
</ul>
<p><br /></p>
<h2 id="pages--assets">Pages &amp; Assets</h2>
<hr />
<p>Pages and all assets defined in the UI Kits are served by the app using both blueprints:</p>
<ul>
<li><em>Home Blueprint</em> manage the static assets - <code class="highlighter-rouge">app/base/static/assets</code></li>
<li>
<p><em>Home Blueprint</em> store the layout <code class="highlighter-rouge">master pages</code>, HTML chunks (footer. header, scripts) and <code class="highlighter-rouge">login, registration</code> pages</p>
</li>
<li><em>Base Blueprint</em> serve the HTML pages (index, page-404, etc) and the rest of the pages defined in the UI kit.</li>
</ul>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt; PROJECT ROOT <span class="o">&gt;</span>
|
|-- app/
| |-- base/ <span class="c"># Base Blueprint</span>
| | |-- static/assets/
| | | |-- css/ <span class="c"># UI Kit css</span>
| | | |-- JS/ <span class="c"># Javascript files</span>
| | | |-- images/ <span class="c"># images used by the app</span>
| | | |-- scss/ <span class="c"># SCSS files (if any)</span>
| | |
| | |-- templates/ <span class="c"># Templates used to render pages</span>
| | |
| | |-- includes/ <span class="c">#</span>
| | | |-- navigation.html <span class="c"># Top menu component</span>
| | | |-- sidebar.html <span class="c"># Sidebar component</span>
| | | |-- footer.html <span class="c"># App Footer</span>
| | | |-- scripts.html <span class="c"># Scripts common to all pages</span>
| | |
| | |-- layouts/ <span class="c"># Master pages</span>
| | | |-- base-fullscreen.html <span class="c"># Used by Authentication pages</span>
| | | |-- base.html <span class="c"># Used by common pages</span>
| | |
| | |-- accounts/ <span class="c"># Authentication pages</span>
| | |-- login.html <span class="c"># Login page</span>
| | |-- register.html <span class="c"># Registration page</span>
| |
| |-- home/ <span class="c"># Home Blueprint - serve app pages (private area)</span>
| |-- templates/ <span class="c"># UI Kit Pages</span>
| |
| |-- index.html <span class="c"># Default page</span>
| |-- page-404.html <span class="c"># Error 404 - mandatory page</span>
| |-- page-500.html <span class="c"># Error 500 - mandatory page</span>
| |-- page-403.html <span class="c"># Error 403 - mandatory page</span>
| |-- <span class="k">*</span>.html <span class="c"># All other HTML pages</span>
|
|-- <span class="k">************************************************************************</span>
</code></pre></div></div>
<p><br /></p>
<h2 id="data-structures">Data Structures</h2>
<hr />
<p>The Flask starter exposes a short-list with data structures used globally across the app:</p>
<p><br /></p>
<h3 id="current_user-object"><code class="highlighter-rouge">current_user</code> object</h3>
<p>Constructed by <a href="https://flask-login.readthedocs.io/en/latest/">Flask-Login</a> can be used to detect if the current request is executed by an authenticated user or not. The object has global visibility and can be used in all app controllers and handlers but also in views.</p>
<p><br /></p>
<blockquote>
<p><strong>How it works</strong></p>
</blockquote>
<p><code class="highlighter-rouge">app/base/models.py</code> define the callback functions required by <strong>Flask-Login</strong> library:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: app/base/models.py
</span>
<span class="o">@</span><span class="n">login_manager</span><span class="p">.</span><span class="n">user_loader</span>
<span class="k">def</span> <span class="nf">user_loader</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
<span class="k">return</span> <span class="n">User</span><span class="p">.</span><span class="n">query</span><span class="p">.</span><span class="n">filter_by</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="nb">id</span><span class="p">).</span><span class="n">first</span><span class="p">()</span>
<span class="o">@</span><span class="n">login_manager</span><span class="p">.</span><span class="n">request_loader</span>
<span class="k">def</span> <span class="nf">request_loader</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">form</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'username'</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">.</span><span class="n">query</span><span class="p">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">).</span><span class="n">first</span><span class="p">()</span>
<span class="k">return</span> <span class="n">user</span> <span class="k">if</span> <span class="n">user</span> <span class="k">else</span> <span class="bp">None</span>
</code></pre></div></div>
<p><br /></p>
<blockquote>
<p><strong>Usage in contoler</strong> (Sample file)</p>
</blockquote>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">def</span> <span class="nf">sample_method</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="c1"># Redirect guests users to login page
</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">current_user</span><span class="p">.</span><span class="n">is_authenticated</span><span class="p">:</span>
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'login'</span><span class="p">))</span>
</code></pre></div></div>
<p><br /></p>
<blockquote>
<p><strong>Usage in view</strong></p>
</blockquote>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"collapse navbar-collapse"</span> <span class="na">id=</span><span class="s">"navigation"</span><span class="nt">&gt;</span>
<span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"navbar-nav ml-auto"</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- The Usage of &lt;current_user&gt; object --&gt;</span>
<span class="c">&lt;!-- Html chunk rendered for guests users--&gt;</span>
<span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item "</span><span class="nt">&gt;</span>
<span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">""</span> <span class="na">class=</span><span class="s">"nav-link"</span><span class="nt">&gt;</span>
<span class="nt">&lt;i</span> <span class="na">class=</span><span class="s">"tim-icons icon-laptop"</span><span class="nt">&gt;&lt;/i&gt;</span> Register
<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item "</span><span class="nt">&gt;</span>
<span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">""</span> <span class="na">class=</span><span class="s">"nav-link"</span><span class="nt">&gt;</span>
<span class="nt">&lt;i</span> <span class="na">class=</span><span class="s">"tim-icons icon-single-02"</span><span class="nt">&gt;&lt;/i&gt;</span> Login
<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>
<p><br /></p>
<h2 id="flask-resources"><a href="https://palletsprojects.com/p/flask/">Flask</a> resources</h2>
<hr />
<ul>
<li><a href="https://palletsprojects.com/p/flask/">Flask</a> - the official website</li>
<li><a href="https://www.creative-tim.com/templates/flask">Flask Templates</a> - index provided by Creative-Tim</li>
</ul>
<p><br /></p>
</main>
</div>
</div>
<!-- Core JS Files -->
<script src="../../../assets/js/core/jquery.min.js" ></script>
<script src="../../../assets/js/core/popper.min.js" ></script>
<script src="../../../assets/js/core/bootstrap.min.js" ></script>
<script src="../../../assets/js/plugins/dashboard/free/perfect-scrollbar.jquery.min.js" ></script>
<!-- Google Maps Plugin -->
<!-- Place this tag in your head or just before your close body tag. -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE"></script>
<!-- Chart JS -->
<script src="../../../assets/js/plugins/dashboard/free/chartjs.min.js"></script>
<!-- Notifications Plugin -->
<script src="../../../assets/js/plugins/dashboard/free/bootstrap-notify.js"></script>
<!-- Control Center for Black Dashboard: parallax effects, scripts for the example pages etc --><script src="../../../assets/js/dashboard-free.js?v=1.0.0"></script><!-- Black Dashboard DEMO methods, don't include it in your project! -->
<script src="../../../assets/demo/dashboard/free/demo.js"></script>
<script>
$(document).ready(function(){
$().ready(function(){
$sidebar = $('.sidebar');
$navbar = $('.navbar');
$main_panel = $('.main-panel');
$full_page = $('.full-page');
$sidebar_responsive = $('body > .navbar-collapse');
sidebar_mini_active = true;
white_color = false;
window_width = $(window).width();
fixed_plugin_open = $('.sidebar .sidebar-wrapper .nav li.active a p').html();
$('.fixed-plugin a').click(function(event){
if($(this).hasClass('switch-trigger')){
if(event.stopPropagation){
event.stopPropagation();
}
else if(window.event){
window.event.cancelBubble = true;
}
}
});
$('.fixed-plugin .background-color span').click(function(){
$(this).siblings().removeClass('active');
$(this).addClass('active');
var new_color = $(this).data('color');
if($sidebar.length != 0){
$sidebar.attr('data',new_color);
}
if($main_panel.length != 0){
$main_panel.attr('data',new_color);
}
if($full_page.length != 0){
$full_page.attr('filter-color',new_color);
}
if($sidebar_responsive.length != 0){
$sidebar_responsive.attr('data',new_color);
}
});
$('.switch-sidebar-mini input').on("switchChange.bootstrapSwitch", function(){
var $btn = $(this);
if(sidebar_mini_active == true){
$('body').removeClass('sidebar-mini');
sidebar_mini_active = false;
blackDashboard.showSidebarMessage('Sidebar mini deactivated...');
}else{
$('body').addClass('sidebar-mini');
sidebar_mini_active = true;
blackDashboard.showSidebarMessage('Sidebar mini activated...');
}
// we simulate the window Resize so the charts will get updated in realtime.
var simulateWindowResize = setInterval(function(){
window.dispatchEvent(new Event('resize'));
},180);
// we stop the simulation of Window Resize after the animations are completed
setTimeout(function(){
clearInterval(simulateWindowResize);
},1000);
});
$('.switch-change-color input').on("switchChange.bootstrapSwitch", function(){
var $btn = $(this);
if(white_color == true){
$('body').addClass('change-background');
setTimeout(function(){ $('body').removeClass('change-background');
$('body').removeClass('white-content'); }, 900);
white_color = false;
}else{
$('body').addClass('change-background');
setTimeout(function(){ $('body').removeClass('change-background');
$('body').addClass('white-content');}, 900);
white_color = true;
}
});
$('.light-badge').click(function(){
$('body').addClass('white-content');
});
$('.dark-badge').click(function(){
$('body').removeClass('white-content');
});
});
});
</script>
<script src="../../../assets/demo/docs.min.js"></script>
<script src="../../../assets/demo/vendor/anchor.min.js"></script>
<script src="../../../assets/demo/vendor/clipboard.min.js"></script>
<script src="../../../assets/demo/vendor/holder.min.js"></script>
<script src="../../../assets/demo/src/application.js"></script>
<script>
$(document).ready(function(){
if($('#lineChartExample').length != 0){
demo.initDocChart();
}
});
</script>
<script>
Holder.addTheme('gray', {
bg: '#777',
fg: 'rgba(255,255,255,.75)',
font: 'Helvetica',
fontweight: 'normal'
})
</script>
<script src="https://cdn.trackjs.com/agent/v3/latest/t.js"></script><script>
window.TrackJS &&
TrackJS.install({
token: "ee6fab19c5a04ac1a32a645abde4613a",
application: "black-dashboard-free"
});
</script>
</body>
</html>