Learning Flask


 

Learning Flask (All-In-One Guide)

Flask is a framework for web development based on Python. It is no room for other languages like JavaScript, PHP, and so on...

Using powerful language with numerous amount of such amazing packages, make Flask one of the most favorable framework among web developers!

Here's my notes on learning Flask, I tried to be comprehensive, short and of course applicable, preventing to explain hard and less useful concepts and techniques.

#create a virtual environment in command prompt (venv_name is your project name):
python -m venv venv_name
#activate the venv:
venv_name\Scripts\activate
#Install the flask within the venv area:
pip install Flask
#create a py file and write these part of code:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return '<h1>Hello, World!</h1>'
#save it as hello.py
#before runnning the app, must export the flask_app in cmdlet:
export FLASK_APP=hello.py
flask run
#* Running on http://127.0.0.1:5000/
#or just:
python hello.py
#or this in windows cmdlet:
set FLASK_APP=hello.py
#or this:
export FLASK_APP=hello.py
python -m flask run
#head over to http://127.0.0.1:5000/ after the running previous line in cmdlet
#If you have the debugger disabled or trust the users on your network, 
#you can make the server publicly available simply 
#by adding --host=0.0.0.0 to the command line:
flask run --host=0.0.0.0
#or in debug mode:
set FLASK_ENV=development
flask run

Flask uses html in this way:

#create a folder named "template" and copy your htmls with css and js codes/links into it.
#replace every variable segment with {{ var }} tag
#Here’s a simple example of how to render a template: (in py file)
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')    #add name after /hello/ in address bar
def hello(name=None):
    return render_template('hello.html'name=name) #passing arg to html file

 in html file:

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1> #this name comes from function in app.py
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

uploading files:

set the enctype="multipart/form-data" attribute on your HTML form

then you can access those files by looking at the files attribute on the request object. 

in app.py:

from flask import request
from werkzeug.utils import secure_filename

@app.route('/upload'methods=['GET''POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename))

Reading/Storing cookies:

 

from flask import request
@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not to get a
    # KeyError if the cookie is missing.

#------------Storing cookies:
from flask import make_response
@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username''the username')
    return resp

For Loops:

<ul class="sitemap">
{%- for item in sitemap recursive %}
    <li><a href="{{ item.href|e }}">{{ item.title }}</a>
    {%- if item.children -%}
        <ul class="submenu">{{ loop(item.children) }}</ul>
    {%- endif %}</li>
{%- endfor %}
</ul>

Macros:

For those people that have no experience with MS Word or macro concept at all, a macro is a process that you're going to repeat it several times and preventing wasting of time, you save that process in a piece of code or .py file and call it in Flask. Like this:

#Here’s a small example of a macro that renders a form element:
{% macro m_name(name, value=''type='text'size=20) -%}
    <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}">
{%- endmacro %}
#The macro can then be called like a function in the namespace:
<p>{{ m_name('username') }}</p>
<p>{{ m_name('password'type='password') }}</p>
#if args are not specified, it would use from the defaults
#if defined in a different template, you have to import it first
#to pass a macro to another macro:
{% macro render_dialog(arg1, class='dialog') -%}
        <div class="contents">{{ caller(arg1) }}</div>
{%- endmacro %}

{% call(arg1) render_dialog('Hello World') %}
    {{ arg1.item }} is a simple dialog rendered by using a macro and a call block.
{% endcall %}

 The alternative way to importing components and prevent wasting time, you can import an html file having your component:


#in form.html
{% macro i_name(name, value=''type='text') -%}
    <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}
{%- macro t_name(name, value=''rows=10cols=40) -%}
    <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{ value|e }}</textarea>
{%- endmacro %}

#in other.html
{% import 'forms.html' as forms %}
<dl>
    <dt>Username</dt>    <dd>{{ forms.i_name('username') }}</dd>
    <dt>Password</dt>    <dd>{{ forms.i_name('password'type='password') }}</dd>
</dl>
<p>{{ forms.t_name('comment') }}</p>

Database (connecting to SQL):

#create a db helper (database.py)
#create the db (schema.sql)
#   run this (passing schema to the db cmd): sqlite3  db_name.db < schema.sql
#   open up the db: sqlite3  db_name.db, now can check the db with sql commands

 in app.py

from flask import Flask, render_template, g, request, session, redirect, url_for
from database import get_db #it refers to the database.py file (database helper)
from werkzeug.security import generate_password_hash, check_password_hash
import os

some functions to get data from db:

@app.teardown_appcontext
def close_db(error):
    if hasattr(g, 'sqlite_db'):
        g.sqlite_db.close()

def get_current_user():
    user_result = None

    if 'user' in session:
        user = session['user']

        db = get_db()
        user_cur = db.execute('select id, name, password, expert, admin from users where name = ?', [user])
        user_result = user_cur.fetchone()

    return user_result

 add logic to index, register, login and logout page method :

@app.route('/')
def index():
    user = get_current_user()
    db = get_db()

    questions_cur = db.execute('''select 
                                      questions.id as question_id, 
                                      questions.question_text, 
                                      askers.name as asker_name, 
                                      experts.name as expert_name 
                                  from questions 
                                  join users as askers on askers.id = questions.asked_by_id 
                                  join users as experts on experts.id = questions.expert_id 
                                  where questions.answer_text is not null''')
#questions is a table in questions.db file with sqlite format syntax
    questions_result = questions_cur.fetchall()

    return render_template('home.html'user=user, questions=questions_result)

@app.route('/register'methods=['GET''POST'])
def register():
    user = get_current_user()

    if request.method == 'POST':

        db = get_db()
        existing_user_cur = db.execute('select id from users where name = ?', [request.form['name']])
        existing_user = existing_user_cur.fetchone()

        if existing_user:
            return render_template('register.html'user=user, error='User already exists!')

        hashed_password = generate_password_hash(request.form['password'], method='sha256')
        db.execute('insert into users (name, password, expert, admin) values (?, ?, ?, ?)', [request.form['name'], hashed_password, '0''0'])
        db.commit()

        session['user'] = request.form['name']

        return redirect(url_for('index'))

    return render_template('register.html'user=user)

@app.route('/login'methods=['GET''POST'])
def login():
    user = get_current_user()
    error = None

    if request.method == 'POST':
        db = get_db()

        name = request.form['name']
        password = request.form['password']

        user_cur = db.execute('select id, name, password from users where name = ?', [name])
        user_result = user_cur.fetchone()

        if user_result:

            if check_password_hash(user_result['password'], password):
                session['user'] = user_result['name']
                return redirect(url_for('index'))
            else:
                error = 'The password is incorrect.'
        else:
            error = 'The username is incorrect'

    return render_template('login.html'user=user, error=error)
 
@app.route('/logout')
def logout():
    session.pop('user'None)
    return redirect(url_for('index'))
 

in database.py:

from flask import g
import sqlite3

def connect_db():
    sql = sqlite3.connect('/mnt/c/Users/antho/Documents/question_answer/questions.db')
    sql.row_factory = sqlite3.Row
    return sql

def get_db():
    if not hasattr(g, 'sqlite_db'):
        g.sqlite_db = connect_db()
    return g.sqlite_db

and schema.sql it works as a model for db data. you can create these tables in command prompt using sqlite3 commands:

create table users (
    id integer primary key autoincrement,
    name text not null,
    password text not null,
    expert boolean not null,
    admin boolean not null 
);

create table questions (
    id integer primary key autoincrement,
    question_text text not null,
    answer_text text,
    asked_by_id integer not null,
    expert_id integer not null
);

Deployment

Better to refer to this link.

 

Hope it's helpful...

Hae fun!


Comments