Flask Blueprints Sinhala Guide | Python Web Development | Scalable Apps

Flask Blueprints Sinhala Guide | Python Web Development | Scalable Apps

Building Scalable Flask Apps with Blueprints | Sinhala Guide

ආයුබෝවන් යාළුවනේ! අද අපි කතා කරන්න යන්නේ Python Flask Framework එක භාවිතයෙන් විශාල, සංකීර්ණ web applications හදනකොට ගොඩක් වැදගත් වෙන, ඒ වගේම අපේ code එක පිළිවෙළකට තියාගන්න උදව් වෙන සුපිරි concept එකක් ගැන – ඒ තමයි Flask Blueprints.

Flask කියන්නේ lightweight web framework එකක්. ඒක පොඩි projects වලට නම් නියමයි, ඒත් අපේ application එක ටිකෙන් ටික ලොකු වෙනකොට, routes ගොඩක්, views ගොඩක්, database models ගොඩක් එනකොට, single file එකක හැමදේම තියාගන්න එක හරිම අමාරු වෙනවා. Code එක අවුල් වෙනවා, maintain කරන්න අමාරු වෙනවා, අලුත් features add කරන එකත් වදයක් වෙනවා. මෙන්න මේ වගේ වෙලාවට තමයි Blueprints අපේ ගැලවුම්කාරයා වෙන්නේ!

Flask Blueprints කියන්නේ මොනවාද?

සරලවම කිව්වොත්, Blueprint එකක් කියන්නේ Flask Application එකක "section" එකක්, නැත්නම් "component" එකක් වගේ දෙයක්. හිතන්න, අපේ ගෙදර සැලැස්ම වගේ. මුළු ගේම එක සැලැස්මක අඳිනවා වෙනුවට, අපිට පුළුවන් kitchen එකට වෙනම සැලැස්මක්, bathroom එකට වෙනම සැලැස්මක්, living room එකට වෙනම සැලැස්මක් හදන්න. ඊට පස්සේ මේ හැම සැලැස්මක්ම එකට එකතු කරලා සම්පූර්ණ ගේ හදන්න.

ඒ වගේම Flask Blueprints වලිනුත් වෙන්නේ අපේ Flask Application එකේ "කාර්යයන්" (functionalities) අනුව කොටස් වලට කඩන එක. උදාහරණයක් විදියට, අපිට පුළුවන් user authentication (login, register, logout) අදාල routes, views, templates, static files ඔක්කොම එක auth Blueprint එකකට දාන්න. ඒ වගේම blog posts, comments අදාල දේවල් blog Blueprint එකකට දාන්න. මේවා හැම එකක්ම තමන්ටම වෙන් වුණු කුඩා Flask application එකක් වගේ හැසිරෙනවා, හැබැයි මේවා main Flask application එකට register කරපු ගමන් ඒකෙම කොටස් බවට පත් වෙනවා.

Blueprints භාවිතයෙන් ලැබෙන වාසි:

  • Modularity (කාර්යයන්ට අනුව වෙන් කිරීම): Application එකේ different features (e.g., authentication, posts, admin panel) වෙනම, ස්වාධීන කොටස් විදියට සංවිධානය කරන්න පුළුවන්.
  • Maintainability (නඩත්තු කිරීමේ පහසුව): Code එක කොටස් වලට කැඩිලා තියෙන නිසා, bug fix එකක් කරන්න හරි, අලුත් feature එකක් add කරන්න හරි ලේසියි. අදාල section එකට ගිහින් වැඩේ කරන්න පුළුවන්.
  • Reusability (නැවත භාවිතය): අපි හදන Blueprint එකක් වෙනත් Flask Application එකකදී පවා නැවත භාවිතා කරන්න පුළුවන්. හිතන්න, authentication system එකක් හදලා ඒක project දෙකක පාවිච්චි කරන්න පුළුවන්.
  • Organization (සංවිධානය): Project structure එක පිළිවෙළයි. files හොයාගන්න ලේසියි. Large team projects වලදී මේක අතිශයින් වැදගත්.
  • URL Prefixing (URL වලට මුලින් යමක් එකතු කිරීම): අපේ Blueprints වලට unique URL prefixes දෙන්න පුළුවන්. උදාහරණයක් විදියට, auth Blueprint එකේ හැම route එකක්ම /auth වලින් පටන් ගන්න පුළුවන්. (e.g., /auth/login, /auth/register)

Blueprints භාවිතයෙන් Project එකක් Structure කරමු

දැන් අපි බලමු Blueprint එකක් භාවිතයෙන් අපේ Flask project එක කොහොමද restructure කරන්නේ කියලා. සාමාන්‍යයෙන් Flask app එකක් Blueprint නැතුව හදනකොට හැමදේම එක app.py file එකක තියෙන්න පුළුවන්. එත් ලොකු project එකකට මේක හොඳ නැහැ.

සාමාන්‍ය Flask App එකක් (Blueprint නැතුව):

මුලින්ම අපි බලමු පොඩි Flask app එකක් Blueprint නැතුව කොහොමද තියෙන්නේ කියලා. මේකේදී authentication සහ posts කියන functionalities දෙකම එකම file එකක තියෙනවා කියලා හිතමු.

# app.py (Without Blueprints)
from flask import Flask, render_template, request, redirect, url_for, flash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key_here' # For flashing messages

# --- Authentication Routes ---
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username == 'admin' and password == 'password': # Simple check
            flash('Login successful!', 'success')
            return redirect(url_for('home'))
        else:
            flash('Invalid credentials!', 'danger')
    return render_template('login.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    # Registration logic
    return "Register Page"

@app.route('/logout')
def logout():
    flash('Logged out.', 'info')
    return redirect(url_for('login'))

# --- Post Routes ---
@app.route('/posts')
def posts():
    # Fetch posts from DB
    return "All Posts"

@app.route('/posts/new', methods=['GET', 'POST'])
def new_post():
    # Logic to create a new post
    return "Create New Post"

# --- Other Routes ---
@app.route('/')
def home():
    return render_template('home.html')

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

මේ app.py file එකේ code ටික වැඩි වෙනකොට මේක maintain කරන එක අමාරුයි. ඒක විසඳන්න අපි දැන් Blueprint භාවිතයට ගමු.

Blueprint භාවිතයෙන් Project Structure එකක්:

Blueprint භාවිතයෙන් project එකක් සංවිධානය කරන සාමාන්‍ය ක්‍රමයක් පහතින් දැක්වේ.

your_project_name/
├── app.py                  # Main application instance and Blueprint registration
├── config.py               # Configuration settings
├── static/                 # Static files (CSS, JS, images)
│   ├── css/
│   └── js/
├── templates/              # Base templates
│   └── base.html
│   └── home.html
├── auth/                   # Authentication Blueprint
│   ├── __init__.py         # Defines the auth blueprint
│   ├── routes.py           # Auth related routes (login, register)
│   ├── models.py           # Auth related database models
│   └── templates/          # Auth specific templates
│       ├── login.html
│       └── register.html
├── posts/                  # Posts Blueprint
│   ├── __init__.py         # Defines the posts blueprint
│   ├── routes.py           # Post related routes (view, create, edit)
│   ├── models.py           # Post related database models
│   └── templates/          # Post specific templates
│       ├── view_post.html
│       └── create_post.html
└── __init__.py             # Optionally for a package structure, or for an app factory pattern

Blueprint එකක් නිර්මාණය කරමු:

දැන් අපි බලමු auth Blueprint එක කොහොමද හදන්නේ කියලා.

auth/__init__.py:

from flask import Blueprint

# Define the Blueprint.
# 'auth' is the name of the blueprint.
# __name__ tells Flask where to find associated resources (templates, static files).
auth_bp = Blueprint('auth', __name__, template_folder='templates', static_folder='static')

# Import routes to associate them with the blueprint
from . import routes

auth/routes.py:

from flask import render_template, request, redirect, url_for, flash
from . import auth_bp # Import the blueprint instance from __init__.py

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username == 'admin' and password == 'password':
            flash('Login successful!', 'success')
            return redirect(url_for('main.home')) # Notice 'main.home'
        else:
            flash('Invalid credentials!', 'danger')
    return render_template('login.html')

@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
    # Registration logic here
    flash('Registration page accessed!', 'info')
    return render_template('register.html')

@auth_bp.route('/logout')
def logout():
    flash('You have been logged out.', 'info')
    return redirect(url_for('auth.login')) # Redirect to login route within auth blueprint

මෙහිදී, auth_bp.route() භාවිතයෙන් routes define කර ඇති බව සැලකිලිමත් වන්න. සාමාන්‍යයෙන් app.route() වෙනුවට Blueprint instance එක භාවිත කරනවා.

ඒ වගේම posts Blueprint එකත් මේ විදියටම හදාගන්න පුළුවන්.

posts/__init__.py:

from flask import Blueprint

posts_bp = Blueprint('posts', __name__, template_folder='templates', static_folder='static')

from . import routes

posts/routes.py:

from flask import render_template, request, redirect, url_for, flash
from . import posts_bp # Import the blueprint instance

@posts_bp.route('/')
def index():
    # Fetch all posts logic
    posts = ['Post 1', 'Post 2', 'Post 3'] # Dummy data
    return render_template('posts/index.html', posts=posts)

@posts_bp.route('/<int:post_id>')
def view_post(post_id):
    # Fetch specific post logic
    return f"Viewing Post {post_id}"

@posts_bp.route('/new', methods=['GET', 'POST'])
def create_post():
    # Logic to create a new post
    return "Create New Post"

Main Application එකේ Blueprints Register කරමු:

දැන් අපි හදපු Blueprints, main Flask application එකට register කරන්න ඕන. සාමාන්‍යයෙන් මේකට "Application Factory Pattern" එක භාවිතා කරනවා. මේකෙන් circular imports වගේ ගැටළු වළක්වා ගන්නත් පුදුවන්.

app.py (Main Application File):

from flask import Flask, render_template

def create_app():
    app = Flask(__name__)
    app.config.from_pyfile('config.py') # Load configuration from config.py

    # Import Blueprints
    from auth import auth_bp
    from posts import posts_bp

    # Register Blueprints
    # url_prefix='something' can be used to prefix all routes in the blueprint
    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(posts_bp, url_prefix='/posts')

    # Main routes not associated with any specific Blueprint
    @app.route('/')
    def home():
        return render_template('home.html')

    return app

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

config.py:

SECRET_KEY = 'your_super_secret_key_for_flask_sessions'
# Add other configurations like database connection strings here

මේ ආකාරයට application factory pattern එක භාවිතා කරනකොට, app = Flask(__name__) කියන instance එක global variable එකක් විදියට තියෙනවා වෙනුවට, create_app() function එක ඇතුළත initialize වෙනවා. මේක circular imports වළක්වා ගන්න ගොඩක් උදව් වෙනවා.

URL Generation:

Blueprint එකක් භාවිතා කරනකොට url_for() function එක පාවිච්චි කරන විදිය වෙනස් වෙනවා. කලින් url_for('login') කියලා දැම්මා නම්, දැන් url_for('blueprint_name.view_function_name') කියලා දාන්න ඕන. උදාහරණයක් විදියට:

  • url_for('auth.login') - auth Blueprint එකේ login view function එකට.
  • url_for('posts.index') - posts Blueprint එකේ index view function එකට.
  • url_for('home') - main app එකේ home view function එකට (කිසිම Blueprint එකකට අයිති නැති නිසා).

Circular Imports සහ විසඳුම්

Flask Blueprints භාවිත කරනකොට, මුලින්ම ගොඩක් දෙනෙක්ට මුණගැහෙන ප්‍රශ්නයක් තමයි Circular Imports. මේක වෙන්නේ එක file එකක් තව file එකක් import කරනකොට, ඒ import කරපු file එකත් මුලින්ම import කරපු file එකම ආයෙත් import කරන්න උත්සාහ කරනකොට.

සරල උදාහරණයක්: * app.py එක auth/__init__.py import කරනවා. * auth/__init__.py එක auth/routes.py import කරනවා. * auth/routes.py එක app instance එක import කරන්න උත්සාහ කරනවා (ඒකෙන් database එකට access ගන්න වගේ දෙයක්). * එතකොට app.py ලෝඩ් වෙන්න කලින් auth/routes.py එක ලෝඩ් වෙන්න උත්සාහ කරනවා, ඊට කලින් app.py ලෝඩ් වෙන්න ඕන නිසා, මේක චක්‍රයක් (cycle) බවට පත් වෙනවා.

මෙය වළක්වා ගන්න ක්‍රම:

current_app Proxy භාවිතය:Flask provides a current_app proxy එකක්. මේකෙන් active application context එක ඇතුළේ තියෙන application instance එකට access ගන්න පුළුවන්. ඒ නිසා, අපිට app object එක directly import නොකර, ඒකේ properties (config, extensions) වලට access ගන්න පුළුවන්. මේක ගොඩක් වෙලාවට Flask extensions (e.g., Flask-SQLAlchemy) වලදී දකින දෙයක්.

# auth/routes.py (Using current_app)
from flask import render_template, request, redirect, url_for, flash, current_app
from . import auth_bp

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # Access config values from the main app
        secret_key = current_app.config['SECRET_KEY']
        # ... use secret_key ...
    return render_template('login.html')

මේ ක්‍රමයත් circular imports වළක්වා ගන්න උදව් වෙනවා, විශේෂයෙන්ම global variables විදියට තියෙන app instance එකට access ඕන වෙන තැන් වලදී.

Lazy Imports (Functions ඇතුළත Imports):සමහර වෙලාවට, අපිට app instance එකක් හෝ වෙනත් Blueprint එකක් ඇතුලේ define කරපු දෙයක් route function එකක් ඇතුළේදී අවශ්‍ය වෙන්න පුළුවන්. ඒ වගේ වෙලාවට, global scope එකේ import කරනවා වෙනුවට, අදාල function එක ඇතුළේ import කරන්න පුළුවන්. හැබැයි මේක හැමවිටම හොඳම විසඳුමක් නෙවෙයි, code එක අවුල් වෙන්න පුළුවන්.

# auth/routes.py (Example of lazy import - NOT generally recommended)
from flask import render_template, request, redirect, url_for, flash
from . import auth_bp

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # This import only happens when login() is called
        from app import db # Assuming 'db' is initialized in app.py
        user = db.session.query(...).filter_by(username=request.form['username']).first()
        # ... rest of the login logic
    return render_template('login.html')

මෙය circular import ගැටළුව තාවකාලිකව විසඳුවත්, code readability එක අඩු කරනවා. ඒ නිසා application factory pattern එක තමයි වඩාත් හොඳ ක්‍රමය.

Application Factory Pattern (නිර්දේශිතයි):අපි කලින් දැක්කා වගේ, create_app() කියන function එකක් ඇතුලේ Flask app instance එක හදලා, Blueprints register කරන එක මේ ගැටළුවට හොඳම විසඳුමක්. මේ ක්‍රමයේදී, Blueprints import කරන්නේ create_app() function එක ඇතුළත නිසා, app object එක සම්පූර්ණයෙන්ම initialize වුනාට පස්සේ තමයි ඒ imports සිද්ධ වෙන්නේ. ඒ නිසා circular import එකක් ඇතිවෙන්නේ නැහැ.

# __init__.py (top-level, or app.py if not using package structure)
from flask import Flask

def create_app():
    app = Flask(__name__)
    app.config.from_pyfile('config.py')

    from .auth import auth_bp
    from .posts import posts_bp

    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(posts_bp, url_prefix='/posts')

    # ... other app configurations and routes ...

    return app

Scalability සඳහා හොඳම ක්‍රම (Best Practices)

Blueprints කියන්නේ අපේ Flask application එකක් scale කරන්න තියෙන හොඳම tool එකක්. ඒකෙන් උපරිම ප්‍රයෝජන ගන්න පුළුවන් විදියට අපි ඒක භාවිතා කරන්න ඕන.

  1. Blueprint එකක් එක් Functionality එකකට සීමා කරන්න (Keep Blueprints Focused):ඔබේ Blueprint එකක් හදනකොට, ඒක එකම කාර්යයකට (single functionality) පමණක් සීමා කරන්න. උදාහරණයක් විදියට, auth Blueprint එකට authentication logic විතරක් තියෙන්න ඕන. posts Blueprint එකට blog posts management logic විතරක් තියෙන්න ඕන. මේකෙන් code එක organize වෙනවා වගේම, code එක maintain කරන එකත් ලේසි වෙනවා.
  2. url_prefix භාවිත කරන්න:app.register_blueprint() කරනකොට url_prefix parameter එක අනිවාර්යයෙන්ම භාවිතා කරන්න. මේකෙන් ඔබේ Blueprints වල routes වලට unique prefixes add කරන්න පුළුවන්. app.register_blueprint(auth_bp, url_prefix='/auth') මේකෙන් auth Blueprint එකේ තියෙන /login route එක /auth/login බවට පත් වෙනවා. මේක URL එක පිළිවෙළකට තියාගන්න වගේම, routes confuse වීම වළක්වා ගන්නත් උදව් වෙනවා.
  3. Centralized Configuration (එක තැනකින් Configuration):config.py වගේ file එකක් භාවිතා කරලා, ඔබේ application එකේ සියලුම configuration settings එක තැනක තියාගන්න. මේකෙන් config values වෙනස් කරන එක ලේසි වෙනවා වගේම, different environments (development, production) වලට වෙනස් config values manage කරන එකත් පහසු වෙනවා. app.config.from_pyfile('config.py') වගේ එකක් භාවිතා කරන්න.
  4. Separate Database Models/Services (වෙනම Database Models/Services):ඔබේ database models, services, business logic වගේ දේවල් Blueprints වලටම කොටු කරලා තියාගන්න. එහෙමත් නැත්නම් shared folder එකක separate module එකක් විදියට තියාගන්න. මේකෙන් Blueprints අතර dependencies අඩු කරලා, ඒවයේ ස්වාධීනත්වය රැකගන්න පුළුවන්.
  5. Testing Individual Blueprints (වෙන වෙනම Test කිරීම):Blueprints වල තියෙන modularity නිසා, අපිට පුළුවන් ඒවා වෙන වෙනම test කරන්න. මේකෙන් test cases ලිවීම පහසු වෙනවා වගේම, application එකේ specific functionalities වල bugs හොයාගන්නත් ලේසි වෙනවා.
  6. Templates සහ Static Files සංවිධානය:සෑම Blueprint එකක්ම තමන්ටම වෙන් වූ templates සහ static folders තියාගන්න පුළුවන්. Flask automatically ඒ templates සහ static files හොයාගන්නවා. මේකෙන් resource names (e.g., style.css) confuse වීම වළක්වා ගන්න පුළුවන්. Main application එකට templates/base.html වගේ shared templates තියාගන්න පුළුවන්.Blueprint එකක් ඇතුලෙන් template එකක් load කරනකොට, render_template('blueprint_name/template.html') වගේ දෙයක් භාවිතා කරනවා වෙනුවට, Blueprint එකේ template_folder specify කරලා තියෙන නිසා render_template('login.html') වගේ සරලව භාවිතා කරන්න පුළුවන්. ඒත් වෙනත් Blueprint එකක template එකක් load කරනවා නම්, render_template('auth/login.html') වගේ path එක දෙන්න වෙනවා (එතකොට main app එකේ templates folder එක ඇතුලේ auth කියලා folder එකක් බලනවා).

නිගමනය (Conclusion)

Flask Blueprints කියන්නේ විශාල Flask applications හදනකොට අනිවාර්යයෙන්ම දැනගෙන ඉන්න ඕන concept එකක්. මේකෙන් අපේ code එක modular, maintainable, reusable, සහ scalable විදියට හදන්න පුළුවන්. මුලින්ම මේක ටිකක් සංකීර්ණ වගේ දැනුණත්, පුරුදු වෙනකොට මේකේ තියෙන පහසුව සහ කාර්යක්ෂමතාව ඔබට හොඳින්ම තේරේවි.

අපි මේ tutorial එකෙන් Flask Blueprints කියන්නේ මොකක්ද, ඒවා project එකක structure කරන්නේ කොහොමද, circular imports වගේ ගැටළු විසඳන්නේ කොහොමද, සහ scalability සඳහා හොඳම ක්‍රම මොනවාද කියන දේවල් ගැන කතා කළා.

දැන් ඔබ සූදානම් විශාල Flask projects confidently පටන් ගන්න! මේක ඔබේ ඊළඟ project එකේදී try කරලා බලන්න. ඒ වගේම, මේ ගැන ඔබට තියෙන අත්දැකීම්, ප්‍රශ්න, හෝ අදහස් පහතින් comment කරන්න. අපි හැමෝටම මේ ගැන තවදුරටත් ඉගෙන ගන්න ඒක උදව් වේවි!

සුභ දවසක්!