🏠 Home / Hub

🌶️ Python 10 — Flask Framework

← Python Menu · ← Prev: Django

Flask ဆိုတာ: Minimalist micro-framework ပါ။ Django ထက် light weight, freedom ပိုများ၊ app logic ကိုကိုယ်တိုင် organize လုပ်ရတယ်။ Small APIs, microservices, prototypes တွင် popular ဖြစ်တယ်။

1. Setup & Hello World

# venv နဲ့ Flask install
python -m venv venv
source venv/bin/activate    # Windows: venv\Scripts\activate
pip install flask

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return '<h1>Hello Flask!</h1>'

@app.route('/about')
def about():
    return '<p>About page</p>'

if __name__ == '__main__':
    app.run(debug=True)

# Run
python app.py
# http://127.0.0.1:5000

2. Routes & URL Parameters

from flask import Flask, request

app = Flask(__name__)

# Static route
@app.route('/hello')
def hello():
    return 'Hello!'

# URL variable (path parameter)
@app.route('/user/<username>')
def show_user(username):
    return f'User: {username}'

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post ID: {post_id}'

# Query string: /search?q=python&page=2
@app.route('/search')
def search():
    q    = request.args.get('q', '')
    page = request.args.get('page', 1, type=int)
    return f'Search: {q}, Page: {page}'

# HTTP methods
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        return f'Logged in as {username}'
    return '''
        <form method="post">
            <input name="username" placeholder="Username">
            <input type="password" name="password">
            <button type="submit">Login</button>
        </form>
    '''

3. Templates (Jinja2)

# app.py
from flask import render_template

@app.route('/posts')
def posts():
    items = [
        {'title': 'Flask Intro', 'author': 'Mg Mg'},
        {'title': 'Python Tips',  'author': 'Aye Aye'},
    ]
    return render_template('posts.html', posts=items, count=len(items))

# templates/base.html
<!DOCTYPE html>
<html>
<head><title>{% block title %}Site{% endblock %}</title></head>
<body>
  <nav><a href="/">Home</a> | <a href="/posts">Posts</a></nav>
  {% block content %}{% endblock %}
</body>
</html>

# templates/posts.html
{% extends "base.html" %}
{% block title %}Posts ({{ count }}){% endblock %}
{% block content %}
  <h1>{{ count }} Posts</h1>
  {% for post in posts %}
    <div>
      <h2>{{ post.title }}</h2>
      <p>by {{ post.author }}</p>
    </div>
  {% endfor %}
{% endblock %}

Jinja2 Filters

{{ text | upper }}        → UPPERCASE
{{ text | lower }}        → lowercase
{{ text | truncate(50) }} → shorten
{{ date | strftime('%Y-%m-%d') }}
{{ price | round(2) }}
{{ list | length }}
{{ value | default('N/A') }}
{% if user.is_admin %}Admin{% endif %}

4. Flask REST API (JSON)

from flask import Flask, jsonify, request

app = Flask(__name__)

# In-memory store (real app: database)
posts = [
    {'id': 1, 'title': 'Flask Basics', 'content': 'Hello!'},
    {'id': 2, 'title': 'REST APIs',    'content': 'JSON!'},
]

@app.route('/api/posts', methods=['GET'])
def get_posts():
    return jsonify({'posts': posts, 'total': len(posts)})

@app.route('/api/posts/<int:post_id>', methods=['GET'])
def get_post(post_id):
    post = next((p for p in posts if p['id'] == post_id), None)
    if not post:
        return jsonify({'error': 'Not found'}), 404
    return jsonify(post)

@app.route('/api/posts', methods=['POST'])
def create_post():
    data = request.get_json()
    if not data or 'title' not in data:
        return jsonify({'error': 'title required'}), 400
    new_post = {
        'id':      len(posts) + 1,
        'title':   data['title'],
        'content': data.get('content', ''),
    }
    posts.append(new_post)
    return jsonify(new_post), 201

@app.route('/api/posts/<int:post_id>', methods=['PUT'])
def update_post(post_id):
    post = next((p for p in posts if p['id'] == post_id), None)
    if not post:
        return jsonify({'error': 'Not found'}), 404
    data = request.get_json()
    post.update(data)
    return jsonify(post)

@app.route('/api/posts/<int:post_id>', methods=['DELETE'])
def delete_post(post_id):
    global posts
    posts = [p for p in posts if p['id'] != post_id]
    return jsonify({'message': 'Deleted'})

5. SQLAlchemy ORM with Flask

pip install flask-sqlalchemy

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
# PostgreSQL: 'postgresql://user:pass@localhost/dbname'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

# Model
class Post(db.Model):
    id       = db.Column(db.Integer, primary_key=True)
    title    = db.Column(db.String(200), nullable=False)
    content  = db.Column(db.Text)
    created  = db.Column(db.DateTime, default=datetime.utcnow)

    def to_dict(self):
        return {'id': self.id, 'title': self.title,
                'content': self.content,
                'created': self.created.isoformat()}

# DB init (run once)
with app.app_context():
    db.create_all()

# Queries
@app.route('/api/posts')
def get_all():
    posts = Post.query.order_by(Post.created.desc()).all()
    return jsonify([p.to_dict() for p in posts])

@app.route('/api/posts', methods=['POST'])
def create():
    data = request.get_json()
    p = Post(title=data['title'], content=data.get('content'))
    db.session.add(p)
    db.session.commit()
    return jsonify(p.to_dict()), 201

@app.route('/api/posts/<int:id>', methods=['DELETE'])
def delete(id):
    p = Post.query.get_or_404(id)
    db.session.delete(p)
    db.session.commit()
    return jsonify({'message': 'Deleted'})

6. Blueprints (App Structure)

# Large apps မှာ routes တွေကို blueprint (module) ခွဲပါ

# auth/routes.py
from flask import Blueprint
auth_bp = Blueprint('auth', __name__)

@auth_bp.route('/login')
def login():
    return 'Login page'

@auth_bp.route('/logout')
def logout():
    return 'Logged out'

# posts/routes.py
from flask import Blueprint
posts_bp = Blueprint('posts', __name__, url_prefix='/posts')

@posts_bp.route('/')
def list():
    return 'All posts'

@posts_bp.route('/<int:id>')
def detail(id):
    return f'Post {id}'

# app.py (register blueprints)
from auth.routes import auth_bp
from posts.routes import posts_bp

app.register_blueprint(auth_bp)
app.register_blueprint(posts_bp)

# Structure
myapp/
├── app.py
├── auth/
│   └── routes.py
├── posts/
│   ├── routes.py
│   └── models.py
└── templates/

7. Error Handling & CORS

from flask import jsonify

# Custom error handlers
@app.errorhandler(404)
def not_found(e):
    return jsonify({'error': 'Not found'}), 404

@app.errorhandler(500)
def server_error(e):
    return jsonify({'error': 'Server error'}), 500

# CORS (frontend request allow)
pip install flask-cors

from flask_cors import CORS
CORS(app)   # all routes allow
# or
CORS(app, resources={r"/api/*": {"origins": "http://localhost:3000"}})

# Environment config
import os
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-secret')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///dev.db')
app.config['DEBUG'] = os.environ.get('DEBUG', 'True') == 'True'

8. Flask vs Django — When to Use

SituationUse FlaskUse Django
Project sizeSmall to mediumMedium to large
Need admin panel❌ Build yourself✅ Auto-generated
API only (no HTML)✅ Great⚠️ DRF adds overhead
Microservice✅ Ideal❌ Too heavy
Full CRUD web app⚠️ More code✅ Batteries included
Learning curveLow (simple)Medium (many concepts)
Flexibility✅ Choose own libs⚠️ Django-way
Auth built-in❌ Flask-Login✅ Full auth system

🎉 Flask Lesson Complete!

Flask → Micro-framework, REST APIs, microservices, lightweight apps

Routes Jinja2 jsonify SQLAlchemy Blueprints CORS

📌 Study Checklist