Flask Blueprints Sinhala Guide | Python Web App Structure & Scalability

Flask Blueprints Sinhala Guide | Python Web App Structure & Scalability

Flask Blueprints: ලොකු Flask Apps හදන්න හොඳම ක්‍රමය | Sinhala Guide

ආයුබෝවන් යාළුවනේ! අද අපි කතා කරන්න යන්නේ Python web development වල තියෙන සුපිරිම concept එකක් ගැන – ඒ තමයි Flask Blueprints. ඔයාලා Flask එක්ක පොඩි project එකක් කරලා ඇති, එතකොට සමහරවිට ඔක්කොම code ටික එක app.py file එකක් ඇතුළේ ලියලා ඇති. ඒක පොඩි project වලට නම් අවුලක් නෑ. ඒත් project එක ලොකු වෙනකොට, features වැඩි වෙනකොට, app.py file එකත් බැලුම් බෝලයක් වගේ ලොකු වෙන්න පටන් ගන්නවා.

එතකොට වෙන්නේ මොකක්ද? Code එක manage කරන්න, අලුත් feature එකක් add කරන්න, නැත්නම් bug එකක් fix කරන්න හරිම අමාරු වෙනවා. Code එක අවුල් වෙලා, එකම file එකේ දහස් ගණන් lines තියෙනකොට බලන්නත් එපා වෙනවා නේද? 😓

මෙන්න මේකට තමයි Flask Blueprints කියන solution එක තියෙන්නේ. Blueprints කියන්නේ ඔබේ Flask application එක විවිධ කොටස් වලට, නැත්නම් "mini-applications" වලට කඩලා, organized විදිහට maintain කරන්න උදව් කරන බලගතු tool එකක්. මේ article එකෙන් අපි බලමු:

  1. Blueprints කියන්නේ මොනවාද? (The theory behind Blueprints)
  2. සරල Flask App එකක් Blueprints වලින් Organize කරමු (Practical refactoring with code examples)
  3. Blueprints එක්ක වැඩ කරනකොට එන පොදු ගැටලු සහ විසඳුම් (Troubleshooting common issues like Circular Imports)
  4. Best Practices: විශාල Flask Apps සඳහා Modularity (How to build scalable Flask applications)

ඔයාලා සූදානම් නම්, අපි පටන් ගමු!

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

සරලව කිව්වොත්, Flask Blueprint එකක් කියන්නේ Flask application එකේ කොටසක් වෙනම, self-contained module එකක් විදිහට define කරන්න පුළුවන් ක්‍රමයක්. හරියට ඔබේ ගෙදර විවිධ කාමර වගේ. සාලෙ, නිදන කාමරය, කුස්සිය වගේ. හැම කාමරයකටම තමන්ගේම වැඩ තියෙනවා, ඒත් අන්තිමට ඒ ඔක්කොම එකතු වෙලා තමයි සම්පූර්ණ ගෙදර හැදෙන්නේ.

ඒ වගේම Blueprint එකකට තමන්ටම කියලා views (routes), templates, static files (CSS, JavaScript), සහ error handlers තියෙන්න පුළුවන්. Blueprint එකක් direct run කරන්න බෑ. ඒවා register කරන්න ඕනේ ප්‍රධාන Flask application එකට. මේකෙන් වෙන්නේ Flask application එක කොටස් වලට බෙදිලා යන එක. උදාහරණයක් විදිහට:

  • User Management: (Login, Register, Profile) වලට වෙනම auth_bp (Blueprint) එකක්.
  • Product Catalog: (View Products, Add Product, Edit Product) වලට තව product_bp එකක්.
  • Admin Panel: (Manage Users, View Reports) වලට තව admin_bp එකක්.

මේ වගේ organize කිරීමෙන් code එක කියවන්න, තේරුම් ගන්න, develop කරන්න හරිම පහසු වෙනවා. ඒ වගේම එකම project එකේ කීප දෙනෙකුට එකට වැඩ කරන්නත් පුළුවන්, එකිනෙකාගේ code එක collide වෙන්නේ නැතුව.

2. සරල Flask App එකක් Blueprints වලින් Organize කරමු

දැන් අපි බලමු practical විදිහට Blueprints කොහොමද use කරන්නේ කියලා. මුලින්ම අපි සාමාන්‍ය Flask app එකක් (Blueprints නැතුව) කොහොමද තියෙන්නේ කියලා බලමු, ඊට පස්සේ ඒක Blueprints වලින් refactor කරමු.

2.1. සාමාන්‍ය Flask App එකක් (Blueprints නැතුව)

පහළ තියෙන්නේ routes කීපයක් තියෙන සරල Flask app එකක්. හැමදේම තියෙන්නේ එක app.py file එකක් ඇතුළේ.

# app.py (Without Blueprints)
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return "Welcome to the Home Page!"

@app.route('/about')
def about():
    return "This is the About Page."

@app.route('/contact')
def contact():
    return "Contact us at [email protected]"

# User related routes
@app.route('/login')
def login():
    return "Login Page"

@app.route('/register')
def register():
    return "Register Page"

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

මේක පොඩි app එකක් වුනාට, හිතන්න මේකට තව routes 50ක්, 100ක් විතර එකතු වුනොත්? Database interactions, form handling, authentication logic ඔක්කොම එකම file එකක තිබ්බොත් වැඩේ කොච්චර අවුල් වෙයිද?

2.2. Blueprints හඳුන්වාදීම

දැන් අපි අපේ application එක Blueprints වලින් organized කරගමු. අපි auth (authentication related routes වලට) සහ views (general public routes වලට) කියලා Blueprints දෙකක් හදාගමු. අපේ project structure එක මේ වගේ වෙන්න ඕනේ:

project_root/
├── app.py
├── auth/                  # Authentication Blueprint folder
│   ├── __init__.py
│   └── auth.py
├── views/                 # General views Blueprint folder
│   ├── __init__.py
│   └── views.py
└── templates/             # Main templates folder
    ├── base.html
    ├── auth/              # Auth Blueprint's templates
    │   ├── login.html
    │   └── register.html
    └── views/             # Views Blueprint's templates
        ├── home.html
        └── dashboard.html

දැන් අපි එක් එක් file එකට code එක ලියමු:

auth/auth.py file එක

මේ Blueprint එක user authentication (Login, Register, Logout) routes ටික handle කරනවා.

# auth/auth.py
from flask import Blueprint, render_template, request, flash, redirect, url_for

# Blueprint එකක් හදාගන්නවා
# 'auth' කියන්නේ Blueprint එකේ name එක
# __name__ කියන්නේ Blueprint එකේ root path එක.
# url_prefix='/auth' කියන්නේ මේ Blueprint එකේ හැම route එකකටම '/auth' prefix එකක් add වෙනවා.
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')

@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': # Simple, insecure check for demonstration
            flash('Login successful!', 'success')
            return redirect(url_for('views.home')) # Redirect to a view in another Blueprint
        else:
            flash('Invalid credentials!', 'danger')
    return render_template('auth/login.html') # Note: Flask will search in auth/templates/login.html first

@auth_bp.route('/register')
def register():
    return render_template('auth/register.html')

@auth_bp.route('/logout')
def logout():
    flash('Logged out successfully!', 'info')
    return redirect(url_for('views.home'))

views/views.py file එක

මේ Blueprint එක general public views (Home, Dashboard) handle කරනවා.

# views/views.py
from flask import Blueprint, render_template, flash

# Blueprint එකක් හදාගන්නවා
# 'views' කියන්නේ Blueprint එකේ name එක
# මේකට url_prefix එකක් දුන්නේ නැති නිසා මේක root path එකේ mount වෙනවා.
views_bp = Blueprint('views', __name__, template_folder='templates')

@views_bp.route('/')
def home():
    flash('Welcome to the Blueprint Home!', 'info')
    return render_template('views/home.html')

@views_bp.route('/dashboard')
def dashboard():
    return render_template('views/dashboard.html')

app.py file එක (අවසානයි)

දැන් අපේ ප්‍රධාන app.py file එකේ කරන්නේ, අපි හදපු Blueprints දෙක import කරලා, ඒවා ප්‍රධාන Flask application එකට register කරන එක විතරයි. බලන්න code එක කොච්චර clean වෙලාද කියලා!

# app.py (With Blueprints)
from flask import Flask

# Blueprints දෙක import කරගන්නවා.
# මේවා auth/auth.py සහ views/views.py files වලින් එන Blueprints.
from auth.auth import auth_bp
from views.views import views_bp

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_super_secret_key_here' # For flash messages

# Blueprints register කරනවා.
# මේකෙන් තමයි Flask application එකට Blueprint routes හඳුන්වා දෙන්නේ.
app.register_blueprint(auth_bp)
app.register_blueprint(views_bp)

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

Templates files (උදාහරණ)

අපේ Templates folder එකත් මේ විදිහට හදාගමු. Flask render_template() function එක Blueprint එකක් ඇතුළේ use කරනකොට, මුලින්ම බලන්නේ ඒ Blueprint එකේ template_folder එකේ (අපි template_folder='templates' කියලා දුන්න නිසා ඒ Blueprint folder එක ඇතුළේ තියෙන templates folder එකේ) අදාළ template file එක තියෙනවද කියලා. එහෙම නැතිනම් ප්‍රධාන app එකේ templates folder එකේ බලනවා. මේ නිසා auth Blueprint එකේ templates auth folder එක ඇතුළෙත්, views Blueprint එකේ templates views folder එක ඇතුළෙත් තියෙන එක හොඳ පුරුද්දක්.

templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}My Flask App{% endblock %}</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        nav a { margin-right: 15px; text-decoration: none; color: #007bff; }
        nav a:hover { text-decoration: underline; }
        .flash { padding: 10px; margin-bottom: 10px; border-radius: 5px; }
        .flash.success { background-color: #d4edda; color: #155724; border-color: #c3e6cb; }
        .flash.info { background-color: #d1ecf1; color: #0c5460; border-color: #bee5eb; }
        .flash.danger { background-color: #f8d7da; color: #721c24; border-color: #f5c6cb; }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('views.home') }}">Home</a> |
        <a href="{{ url_for('auth.login') }}">Login</a> |
        <a href="{{ url_for('auth.register') }}">Register</a> |
        <a href="{{ url_for('auth.logout') }}">Logout</a>
    </nav>
    {% with messages = get_flashed_messages(with_categories=true) %}
        {% if messages %}
            <ul class="flashes">
                {% for category, message in messages %}
                    <li class="flash {{ category }}">{{ message }}</li>
                {% endfor %}
            </ul>
        {% endif %}
    {% endwith %}
    <hr>
    <div class="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

templates/auth/login.html

{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
    <h2>Login Page</h2>
    <form method="POST">
        <label for="username">Username:</label><br>
        <input type="text" id="username" name="username"><br>
        <label for="password">Password:</label><br>
        <input type="password" id="password" name="password"><br><br>
        <input type="submit" value="Login">
    </form>
{% endblock %}

templates/views/home.html

{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
    <h1>Welcome!</h1>
    <p>This is the home page of our Blueprint-powered Flask app.</p>
{% endblock %}

දැන් ඔයාට මේ application එක run කරලා බලන්න පුළුවන්. `python app.py` කියලා run කරලා `http://127.0.0.1:5000/` ට ගියාම `Home` page එක පෙනෙයි. `http://127.0.0.1:5000/auth/login` ට ගියාම `Login` page එක පෙනෙයි. `url_for('views.home')` වගේ `url_for` එක use කරනකොට `Blueprint` එකේ name එක මුලින් දීලා, ඊට පස්සේ `view function` එකේ name එක දෙන්න ඕනේ.

3. Blueprints එක්ක වැඩ කරනකොට එන පොදු ගැටලු සහ විසඳුම්

Blueprints කියන්නේ හරිම powerful, නමුත් ඒවා use කරනකොට පොඩි පොඩි issues එන්න පුළුවන්. ඒ අතරින් බහුලවම එන ගැටලුවක් තමයි Circular Imports.

3.1. Circular Imports (චක්‍රීය ආනයන)

Circular Import එකක් කියන්නේ, Module A එක Module B එක import කරනවා, ඒ වගේම Module B එකත් Module A එක import කරනවා. මේක "import loop" එකක්. Python වලදී මේ වගේ වෙලාවට ImportError එකක් හෝ undefined names වගේ errors එන්න පුළුවන්.

Flask වලදී මේක වෙන්නේ කොහොමද?

  • ඔබේ Blueprint module එකක් (උදා: auth.py) ප්‍රධාන app instance එක app.py එකෙන් direct import කරන්න හැදුවොත්.
  • Blueprint එකක් තව Blueprint එකක් import කරන්න හැදුවොත් (මේක සාමාන්‍යයෙන් කරන්න හොඳ නෑ).

app.py එක auth.py import කරනවා. auth.py එකත් app.py import කරනවා නම් මේක circular import එකක්. Flask වල app instance එකට direct access නැතුවට, config variables වගේ දේවල් access කරන්න ඕන වෙන වෙලාවට මේ වගේ අවුල් ඇතිවෙන්න පුළුවන්.

විසඳුම: current_app proxy එක භාවිතය

Flask වලට current_app කියලා special proxy එකක් තියෙනවා. මේකෙන් පුළුවන් දැනට active වෙලා තියෙන Flask application instance එකට access කරන්න. මේක request context එක ඇතුළේ වැඩ කරන නිසා Circular Import ගැටලු මඟහරවා ගන්න පුළුවන්.

# auth/auth.py (Avoiding Circular Imports with current_app)
from flask import Blueprint, render_template, request, flash, redirect, url_for, current_app

auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # Accessing app config safely without importing 'app' directly
        secret_key = current_app.config['SECRET_KEY']
        print(f"Using secret key: {secret_key}")
        # ... rest of your login logic
        flash('Login successful!', 'success')
        return redirect(url_for('views.home'))
    return render_template('auth/login.html')

මේ විදිහට current_app use කරනකොට, Blueprint modules වලට app instance එක direct import කරන්න ඕන වෙන්නේ නෑ. මේක Circular Imports වළක්වා ගන්න හොඳම ක්‍රමයක්.

3.2. Static Files සහ Templates කළමනාකරණය

Blueprints වලට තමන්ගේම static_folder සහ template_folder specify කරන්න පුළුවන්. මේකෙන් වෙන්නේ ඒ Blueprint එකට අදාළ resources ඒ Blueprint එක ඇතුළේම තියාගන්න පුළුවන් වෙන එක.

# Blueprint එකක් හදනකොට template_folder සහ static_folder specify කරන්න පුළුවන්
auth_bp = Blueprint(
    'auth', 
    __name__, 
    url_prefix='/auth', 
    template_folder='templates', # Looks for templates inside auth/templates/
    static_folder='static'       # Looks for static files inside auth/static/
)

Templates: render_template('auth/login.html') වගේ එකක් use කරනකොට, Flask මුලින්ම බලන්නේ auth Blueprint එකේ template_folder එක ඇතුළේ login.html තියෙනවද කියලා (අපි template_folder='templates' දුන්න නිසා auth/templates/login.html). ඊට පස්සේ තමයි ප්‍රධාන app එකේ templates folder එකේ බලන්නේ. මේ නිසා Template namespaces කරලා තියාගන්න එක හොඳ පුරුද්දක්.

Static Files: url_for() function එක use කරලා Blueprint එකක static files වලට link කරන්න පුළුවන්. උදාහරණයක් විදිහට, auth Blueprint එකේ static/css/style.css file එකට link කරන්න ඕනේ නම්:

{{ url_for('auth.static', filename='css/style.css') }}

මතක තියාගන්න, 'auth' කියන්නේ Blueprint එකේ name එක, 'static' කියන්නේ Flask එකේ static files serve කරන්න තියෙන විශේෂ endpoint එක.

4. Best Practices: Scalable Flask Apps සඳහා Modularity

Blueprints වලින් උපරිම ප්‍රයෝජන ගන්න නම්, මේ best practices ටික follow කරන එක වැදගත්.

Database Management

ඔබේ database models, forms, utilities වගේ දේවල් වෙනම modules වල තියාගන්න. මේවා Blueprint එකක් ඇතුළේ direct define කරනවට වඩා, `models.py`, `forms.py` වගේ files වල තියාගන්න එක හොඳයි. Blueprints වලට අවශ්‍ය නම් මේවා import කරගන්න පුළුවන්. SQLAlchemy වගේ ORM එකක් use කරනකොට, database instance එක Blueprint එකට direct pass කරනවා වෙනුවට, current_app use කරලා app context එක ඇතුළේ access කරන එක circular import ගැටලු වළක්වා ගන්න උදව් කරනවා.

Application Factory Pattern

ඉතා විශාල application වලට, විශේෂයෙන් testing වලට, application factory pattern එකක් use කරන එක හොඳ පුරුද්දක්. මේකේදී create_app() වගේ function එකක් ඇතුළේ Flask app instance එක හදලා, configuration කරලා, Blueprints register කරලා return කරනවා. මේකෙන් app එකේ dependencies manage කරන්න සහ test කරන්න හරිම පහසුයි.

# app.py (using an Application Factory)
from flask import Flask

def create_app():
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'another_super_secret_key'

    from .auth.auth import auth_bp
    from .views.views import views_bp

    app.register_blueprint(auth_bp)
    app.register_blueprint(views_bp)

    return app

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

Naming Conventions

Blueprint names (උදා: auth, views) විස්තරාත්මක (descriptive) සහ unique වෙන්න ඕනේ. url_for('blueprint_name.view_function') වගේ ඒවා use කරනකොට මේ Blueprint name එක හරියටම දෙන්න ඕනේ.

Separation of Concerns

හැම Blueprint එකක්ම එක specific feature set එකක් handle කරන්න ඕනේ. auth Blueprint එකට user authentication විතරක්, products Blueprint එකට product management විතරක්. මේකෙන් code එක maintainability වැඩි වෙනවා, ඒ වගේම අනාගතයේදී වෙන මොඩියුල් එකකට move කරන්න වුනත් පහසුයි.

පැහැදිලි Module Organization

ඔබේ project structure එක හැමෝටම තේරෙන විදිහට clear වෙන්න ඕනේ. අපි උඩින් පෙන්නපු විදිහට auth/, views/ වගේ folders හදලා, ඒ ඒ Blueprint එකට අදාළ files (views, templates, static) ඒ folder එක ඇතුළේම තියාගන්න. මේකෙන් Codebase එක clean වෙනවා, අලුත් developer කෙනෙකුට වුනත් project එක ඉක්මනින් තේරුම් ගන්න පුළුවන්.

නිගමනය

හරි, දැන් ඔයාලට Flask Blueprints කියන්නේ මොනවාද, ඒවා කොහොමද use කරන්නේ, සහ ඒවායින් ඔබේ Flask application එක කොච්චර modular සහ scalable කරගන්න පුළුවන්ද කියලා හොඳ අවබෝධයක් ලැබෙන්න ඇති කියලා හිතනවා. Blueprints කියන්නේ Flask හි තියෙන වටිනාම features වලින් එකක්. මේක හරියට use කරන එකෙන් ඔබේ code එකේ quality එක, maintainability එක, සහ team collaboration වල පහසුව විශාල ලෙස වැඩි කරගන්න පුළුවන්.

මුලදී Circular Imports වගේ පොඩි පොඩි දේවල් ගැන සැලකිලිමත් වෙන්න වුනත්, ඒවාට සරල විසඳුම් තියෙනවා (current_app මතක තියාගන්න!). අන්තිමට ලැබෙන clean, organized codebase එකට ඒ පොඩි මහන්සිය වටිනවා.

ඉතින්, ඔයාලගේ ඊළඟ Flask project එකට Blueprints පාවිච්චි කරන්න අමතක කරන්න එපා! 🚀 මේකෙන් ලැබෙන වෙනස ඔයාලටම බලාගන්න පුළුවන්. මේ ගැන ඔයාලගේ අත්දැකීම්, ප්‍රශ්න, නැත්නම් අලුත් අදහස් පහළ comment section එකේ දාන්න. අපි කතා කරමු!

Happy Coding! 😊