Flask Blueprints Sinhala Tutorial | Larger Flask Apps Structuring Guide

කොහොමද යාලුවනේ!
අද අපි කතා කරන්න යන්නේ Flask Web Development වලදී ගොඩක් වැදගත් වෙන, ඒ වගේම ලොකු Apps හදනකොට නැතුවම බැරි දෙයක් ගැන – ඒ තමයි Flask Blueprints. පොඩි Flask App එකක් හදනකොට app.py
එකේම ඔක්කොම ලියලා වැඩේ කරගන්න පුළුවන් වුනත්, App එක ටිකෙන් ටික ලොකු වෙනකොට ඒක භයානක විදියට අවුල් වෙනවා. අන්න ඒ වගේ වෙලාවට තමයි Blueprints කියන concept එක අපේ පිහිටට එන්නේ.
මේ Guide එකෙන් අපි Flask Blueprints කියන්නේ මොනවාද, ඇයි ඒවා අපිට ඕන, ඒ වගේම අපේ Flask App එකක් Blueprints භාවිතයෙන් Structure කරගන්නේ කොහොමද කියලා විස්තරාත්මකව බලමු. ඒ වගේම Circular Imports වගේ Blueprints එක්ක එන පොඩි Issues විසඳාගන්න හැටි සහ Best Practices කිහිපයකුත් කතා කරමු.
අපි පටන් ගමු!
1. Flask Blueprints කියන්නේ මොනවාද? (What are Flask Blueprints?)
සරලවම කිව්වොත්, Flask Blueprint එකක් කියන්නේ Flask Application එකක කොටසක් (a section or module) විදියට හිතන්න පුළුවන් දෙයක්. හිතන්න, ඔයා ලොකු Building එකක් හදනවා කියලා. ඒ Building එකේ Sales Department එකක්, HR Department එකක්, Production Department එකක් තියෙනවා. මේ හැම Department එකකටම තමන්ගේම කාමර, තමන්ගේම වැඩ තියෙනවා නේද? ඒ වගේම තමයි Flask App එකක්. අපේ App එකේ User Authentication එකට එක කොටසක් (Blueprint එකක්), Blog Posts වලට තව කොටසක්, Admin Dashboard එකට තව කොටසක් වගේ අපිට වෙන වෙනම වෙන් කරලා හදන්න පුළුවන්.
Blueprint එකකට තමන්ගේම Routes (URLs), Templates, Static Files (CSS, JS) වගේ දේවල් අයිති කරගන්න පුළුවන්. පස්සේ අපි මේ හැම Blueprint එකක්ම අපේ ප්රධාන Flask Application Instance එකට 'register' කරනවා. මේකෙන් වෙන්නේ අපේ App එක ගොඩක් සංවිධානාත්මක (organized) වෙන එකයි, ඒ වගේම code එක maintain කරන්න සහ නැවත භාවිත කරන්න (reusability) පහසු වෙන එකයි.
ඇයි අපිට Blueprints ඕන? (Why do we need Blueprints?)
- Code Organization: App එක ලොකු වෙනකොට අපේ code එක එක තැනකට ගොඩ ගැහෙන්නේ නැතුව, වෙන් වෙන් වශයෙන් තියාගන්න පුළුවන්.
- Modularity: App එකේ එක කොටසකට වෙනස්කමක් කරනකොට මුළු App එකටම බලපාන්නේ නැහැ. එක module එකක් අනිකෙන් ස්වාධීන වෙනවා.
- Reusability: හදපු Blueprint එකක් වෙනත් Flask App එකකදී වුණත් පහසුවෙන් පාවිච්චි කරන්න පුළුවන්.
- Scalability: App එක ලොකු වෙනකොට team එකේ කට්ටියට වෙන වෙනම කොටස් වල වැඩ කරන්න පහසුයි. Code Conflicts අඩු වෙනවා.
- URL Prefixing: Blueprints වලට අපිට URL prefix එකක් දෙන්න පුළුවන්. උදාහරණයක් විදියට
/auth
,/admin
,/posts
වගේ.
Blueprints නැතුව පොඩි Flask App එකක් මෙහෙම වෙන්න පුළුවන්:
# app.py (Without Blueprints - Small App Example)
from flask import Flask, render_template, request, redirect, url_for, flash
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
# User Authentication Routes
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'user' and password == 'pass': # Insecure, for example only
flash('Logged in successfully!', 'success')
return redirect(url_for('dashboard'))
else:
flash('Login failed. Check credentials.', 'danger')
return render_template('login.html')
@app.route('/logout')
def logout():
flash('Logged out.', 'info')
return redirect(url_for('index'))
# Blog Posts Routes
@app.route('/posts')
def list_posts():
posts = [{'id': 1, 'title': 'First Post'}, {'id': 2, 'title': 'Second Post'}]
return render_template('posts/list.html', posts=posts)
@app.route('/posts/new')
def new_post():
return render_template('posts/new.html')
# Main routes
@app.route('/')
def index():
return 'Hello, Welcome to the homepage!'
@app.route('/dashboard')
def dashboard():
return 'Welcome to your dashboard!'
if __name__ == '__main__':
app.run(debug=True)
දැන් බලන්න, මේක පොඩි App එකක්. නමුත් login
, logout
, list_posts
, new_post
වගේ Routes ඔක්කොම එක file එකක තියෙනවා. App එක ලොකු වෙනකොට මේක manage කරන එක ගොඩක් අමාරු වෙනවා.
2. Blueprints භාවිතයෙන් Flask App එකක් Structuring කරගමු (Structuring a Flask App with Blueprints)
අපි දැන් බලමු Blueprint එකක් හදලා අපේ App එක organize කරගන්නේ කොහොමද කියලා.
මූලික සංකල්ප (Core Concepts)
Blueprint එකක් හදන්න flask.Blueprint
class එක පාවිච්චි කරනවා.
from flask import Blueprint
# Blueprint එකක් හදන හැටි
# 'auth' කියන්නේ Blueprint එකේ නම, __name__ කියන්නේ Blueprint එක තියෙන module එක.
auth_bp = Blueprint('auth', __name__, url_prefix='/auth')
url_prefix='/auth'
කියන්නේ මේ Blueprint එකේ තියෙන හැම route එකකටම ඉස්සරහින් /auth
එකතු වෙනවා කියන එක. උදාහරණයක් විදියට @auth_bp.route('/login')
route එකේ URL එක වෙන්නේ /auth/login
.
Folder Structure එකක් හදමු (Let's Create a Folder Structure)
ලොකු Flask App එකක් හදනකොට අපිට හොඳ Folder Structure එකක් අත්යවශ්යයි. අපි මෙහෙම Structure එකක් ගැන හිතමු:
my_large_app/
├── .venv/ # Virtual Environment
├── __init__.py # Main application factory
├── config.py # Configuration settings
├── auth/ # Auth Blueprint folder
│ ├── __init__.py # Auth Blueprint definition
│ ├── routes.py # Auth related routes (login, register, logout)
│ └── templates/ # Auth specific templates
│ └── login.html
├── posts/ # Posts Blueprint folder
│ ├── __init__.py # Posts Blueprint definition
│ ├── routes.py # Posts related routes (create, view, edit)
│ └── templates/ # Posts specific templates
│ ├── list.html
│ └── detail.html
├── main/ # Main Blueprint (for homepage, etc.)
│ ├── __init__.py # Main Blueprint definition
│ └── routes.py # Main routes (index)
├── static/ # Global static files
│ ├── css/
│ └── js/
└── run.py # Script to run the application
සැබෑ ලෝකයේ උදාහරණයක් (A Real-World Example)
අපි දැන් කලින් තිබ්බ App එක Blueprints භාවිතයෙන් organize කරමු.
my_large_app/config.py
# config.py
class Config:
SECRET_KEY = 'supersecretkey_for_production_replace_me'
# Other configurations like database URI, etc.
my_large_app/__init__.py
(Application Factory)
මෙතනදී අපි Application Factory Pattern එක පාවිච්චි කරනවා. මේකෙන් වෙන්නේ create_app()
function එකක් ඇතුලේ Flask App එක initialize කරන එක. මේක Test කරන්නත්, Multiple Instances හදන්නත් ගොඩක් පහසුයි.
# __init__.py (in my_large_app directory)
from flask import Flask
from config import Config # Import our Config class
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# Blueprints register කරන්න ඕන මෙතනදී
from my_large_app.auth import bp as auth_bp
app.register_blueprint(auth_bp)
from my_large_app.posts import bp as posts_bp
app.register_blueprint(posts_bp)
from my_large_app.main import bp as main_bp
app.register_blueprint(main_bp)
# අමතර extensions (e.g., SQLAlchemy, Flask-Login) මෙතනදී initialize කරන්න පුළුවන්
# db.init_app(app)
# login_manager.init_app(app)
@app.route('/test/')
def test_page():
return 'This is a test page!'
return app
my_large_app/auth/__init__.py
# auth/__init__.py
from flask import Blueprint
bp = Blueprint('auth', __name__, url_prefix='/auth')
# routes.py file එක import කරනවා
from my_large_app.auth import routes
my_large_app/auth/routes.py
# auth/routes.py
from flask import render_template, request, redirect, url_for, flash
from my_large_app.auth import bp # Import the Blueprint instance
@bp.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
# Registration logic here
flash('Registration successful!', 'success')
return redirect(url_for('auth.login')) # Note 'auth.login' - blueprint name.route_function
return render_template('auth/register.html')
@bp.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'test' and password == 'test':
flash('Logged in successfully!', 'success')
return redirect(url_for('main.index')) # Note 'main.index'
else:
flash('Login failed. Check credentials.', 'danger')
return render_template('auth/login.html')
@bp.route('/logout')
def logout():
flash('Logged out.', 'info')
return redirect(url_for('main.index'))
Template files: my_large_app/auth/templates/auth/register.html
, my_large_app/auth/templates/auth/login.html
(මේවා අපි හදලා නැහැ, නමුත් මේ structure එකෙන් පෙන්නන්නේ Blueprint එකටම අදාළ Templates තියාගන්න පුළුවන් බව)
my_large_app/posts/__init__.py
# posts/__init__.py
from flask import Blueprint
bp = Blueprint('posts', __name__, url_prefix='/posts')
from my_large_app.posts import routes
my_large_app/posts/routes.py
# posts/routes.py
from flask import render_template, request, redirect, url_for, flash
from my_large_app.posts import bp
@bp.route('/')
def list_posts():
posts = [{'id': 1, 'title': 'First Post from Posts BP', 'content': 'Hello world!'}]
return render_template('posts/list.html', posts=posts)
@bp.route('/<int:post_id>')
def view_post(post_id):
post = {'id': post_id, 'title': f'Post {post_id}', 'content': f'Content for post {post_id}'}
return render_template('posts/detail.html', post=post)
@bp.route('/new', methods=['GET', 'POST'])
def new_post():
if request.method == 'POST':
flash('New post created!', 'success')
return redirect(url_for('posts.list_posts'))
return render_template('posts/new.html') # Need to create this template
Template files: my_large_app/posts/templates/posts/list.html
, my_large_app/posts/templates/posts/detail.html
my_large_app/main/__init__.py
# main/__init__.py
from flask import Blueprint
bp = Blueprint('main', __name__)
from my_large_app.main import routes
my_large_app/main/routes.py
# main/routes.py
from flask import render_template, current_app
from my_large_app.main import bp
@bp.route('/')
def index():
return render_template('index.html', app_name=current_app.config['SECRET_KEY'])
@bp.route('/about')
def about():
return 'This is the About page!'
Template file: my_large_app/main/templates/index.html
(or placed in my_large_app/templates/index.html
for global templates)
run.py
(Root of the Project)
# run.py
from my_large_app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
දැන් ඔයාට පුළුවන් my_large_app
folder එකට ගිහින් python run.py
කියලා execute කරලා බලන්න. දැන් අපේ App එකේ Routes වෙන් වෙන් වශයෙන් තිබෙනවා. url_for()
භාවිත කරනකොට 'blueprint_name.route_function_name'
විදියට දෙන්න මතක තියාගන්න. උදාහරණයක් විදියට url_for('auth.login')
.
3. Circular Imports සහ ඒවා විසඳාගැනීම (Circular Imports and How to Solve Them)
Blueprint පාවිච්චි කරනකොට එන්න පුළුවන් පොදු ගැටලුවක් තමයි Circular Imports. මේක වෙන්නේ module A එක module B එක import කරලා, module B එකත් module A එක import කරනකොට.
උදාහරණයක් විදියට, ඔයා my_large_app/auth/routes.py
file එකේ from my_large_app import db
(database instance එක) import කරනවා කියලා හිතන්න. ඊට පස්සේ my_large_app/__init__.py
එකේදී from my_large_app.auth import bp
කියලා Blueprint එක import කරනවා. මේකෙන් Circular Import එකක් ඇති වෙන්න පුළුවන්. Flask extensions භාවිත කරනකොට මේක නිතරම වගේ වෙන දෙයක්.
Circular Imports විසඳාගන්න හැටි:
- Application Factory Pattern එක පාවිච්චි කරන්න: අපි කලින් දැක්කා වගේ,
create_app()
function එකක් ඇතුලේ App එක හදලා, Blueprints සහ Extensions Register කරන එක මේකට හොඳම විසඳුම. මේකෙන් Application Context එක නිවැරදිව manage වෙනවා. - Imports ප්රවේශමෙන් කරන්න: Blueprints වල
__init__.py
file එකේදී අදාලroutes.py
file එක import කරන්නේfrom . import routes
වගේ විදියට. ඒ වගේමcreate_app
එකේදී Blueprints import කරන්නේ function එක ඇතුලේ. මේකෙන් Global Scope එකේදී Circular Imports ඇතිවීම වළක්වනවා. current_app
Proxy එක භාවිත කරන්න: Flask හිcurrent_app
කියන්නේ request එකක් ඇතුලේ දැනට active Flask application instance එකට access කරන්න පුළුවන් proxy එකක්. Global objects (like `db` or `mail`) direct import කරනවා වෙනුවට,current_app.config
වගේ දේවල් පාවිච්චි කරන්න පුළුවන්. Extensions වලදීinit_app(app)
වගේ methods පාවිච්චි කරන්නේ මේක විසඳන්න තමයි.
උදාහරණයක් විදියට, ඔයාට db
(SQLAlchemy instance) එකක් තියෙනවා නම්, ඒක my_large_app/__init__.py
එකේදී initialize කරලා, අනිත් Blueprints වලදී from flask import current_app
භාවිතයෙන් ඒකට access කරන්න පුළුවන්, නැත්නම් Flask-SQLAlchemy වගේ extensions වල db.init_app(app)
වගේ methods පාවිච්චි කරන්න.
4. Blueprints භාවිතයේදී Best Practices (Best Practices when using Blueprints)
Flask App එකක් ලොකුවට සාර්ථකව ගොඩනගන්න නම් මේ Best Practices ගොඩක් වැදගත්:
- Application Factory Pattern:
create_app()
function එකක් පාවිච්චි කරලා App එක initialize කරන්න. මේකෙන් testability, flexibility වැඩි වෙනවා. (අපි කලින් Example එකේදී මේක පාවිච්චි කළා). - Clear Naming Conventions: Blueprints, functions, variables වලට පැහැදිලි නම් දෙන්න.
auth_bp
,posts_bp
වගේ. ඒ වගේම URL prefixes පැහැදිලි වෙන්න ඕන. - Separate Concerns: එක Blueprint එකකින් එක දෙයක් විතරක් කරන්න. Auth Blueprint එකේ User Authentication විතරක් තියෙන්න ඕන. Posts Blueprint එකේ Blog Posts වලට අදාළ දේවල් විතරක් තියෙන්න ඕන. මේක Single Responsibility Principle එකට අනුකූලයි.
- Template සහ Static Files Folder Structure: Blueprint එකකට අදාළ Templates සහ Static Files අදාල Blueprint folder එක ඇතුලෙම තියාගන්න. (e.g.,
my_large_app/auth/templates/auth/login.html
). Flask විසින් මේවා auto-discover කරනවා. - Centralized Configuration:
config.py
file එකක් පාවිච්චි කරලා App එකේ Settings එක තැනකින් manage කරන්න. Environment variables පාවිච්චි කරන්නත් අමතක කරන්න එපා, විශේෂයෙන් Production වලදී. - Error Handling: Global Error Handlers (e.g.,
@app.errorhandler(404)
)create_app()
function එක ඇතුලේ Register කරන්න. එහෙම නැත්නම් Blueprint-specific error handlers පාවිච්චි කරන්න පුළුවන්. - Testing: Application Factory Pattern එක භාවිත කරන නිසා Blueprints වෙන වෙනම Test කරන්න පහසු වෙනවා. Flask Test Client එක මේකට ගොඩක් ප්රයෝජනවත්.
නිගමනය (Conclusion)
Flask Blueprints කියන්නේ ලොකු, සංකීර්ණ Flask Applications ගොඩනගන ඕනෑම කෙනෙකුට අත්යවශ්ය Tool එකක්. මේකෙන් අපේ code එක organize වෙනවා විතරක් නෙවෙයි, maintainability, reusability, සහ scalability කියන දේවල් ගොඩක් වැඩි දියුණු වෙනවා. පොඩි Flask App එකක් වුණත් Blueprints වලින් පටන් ගන්න එක අනාගතයේදී ගොඩක් වාසිදායක වෙන්න පුළුවන්.
අද අපි Blueprints කියන්නේ මොනවාද, ඒවා implement කරන්නේ කොහොමද, folder structure එකක් හදන හැටි, Circular Imports වගේ ගැටලු විසඳාගන්න හැටි, ඒ වගේම Best Practices ගැනත් කතා කළා. දැන් ඔයාට පුළුවන් මේ දැනුම පාවිච්චි කරලා ඔයාගේ ඊළඟ Flask Project එක හොඳට organize කරගන්න.
මේ ගැන ඔයාලගේ අත්දැකීම්, ප්රශ්න පහළින් Comment එකක් විදියට දාගෙන යන්න. ඒ වගේම මේක ඔයාගේ Project එකක implement කරලා බලන්න අමතක කරන්න එපා!
Happy Coding!