Flask SQLAlchemy Sinhala Tutorial | Databases for Web Apps

Flask SQLAlchemy Sinhala Tutorial | Databases for Web Apps

හැඳින්වීම (Introduction)

ආයුබෝවන්, developer යාළුවනේ! වෙබ් ඇප්ලිකේෂන් එකක් හදනකොට දත්ත ගබඩා (data storage) කියන්නේ නැතුවම බැරි දෙයක්. අපේ ඇප් එකේ තියෙන user details, posts, comments වගේ හැම දෙයක්ම ගබඩා කරලා තියාගන්න Database එකක් අත්‍යවශ්‍යයි. Python වල Flask කියන්නේ lightweight, flexible වෙබ් framework එකක්. ඒත්, Flask එකට default වලින් database support එකක් නැහැ. ඒකට තමයි අපි Flask-SQLAlchemy වගේ extensions පාවිච්චි කරන්නේ.

මේ tutorial එකෙන් අපි බලමු Flask ඇප්ලිකේෂන් එකක් ඇතුළේ databases එක්ක වැඩ කරන්න SQLAlchemy කොහොමද පාවිච්චි කරන්නේ කියලා. විශේෂයෙන්ම, අපි Object-Relational Mappers (ORMs) ගැන ඉගෙන ගන්නවා, SQLAlchemy install කරගන්නවා, database models define කරනවා, සහ දත්ත එකතු කරන්න, ලබා ගන්න, update කරන්න, delete කරන්න (CRUD operations) පුරුදු වෙනවා.

මේක අලුතින් Flask සහ databases ගැන ඉගෙන ගන්න කෙනෙක්ට හොඳ ආරම්භයක් වෙයි කියලා මම හිතනවා. එහෙනම්, පටන් ගමු!

ORMs (Object-Relational Mappers) කියන්නේ මොනවාද?

ඔබ දන්නවා ඇති, අපි databases එක්ක කතා කරන්නේ SQL (Structured Query Language) වලින් කියලා. උදාහරණයක් විදියට, database එකකට user කෙනෙක්ව එකතු කරන්න අපි INSERT INTO users (username, email) VALUES ('john_doe', '[email protected]'); වගේ SQL query එකක් ලියනවා. මේක සරල වුණාට, ඇප්ලිකේෂන් එකක් ලොකු වෙනකොට මේ වගේ queries අතින් ලියන එක ටිකක් අමාරු වෙනවා. තව, database එක වෙනස් වුණොත් (උදා: MySQL වෙනුවට PostgreSQL) අපිට queries ටිකත් වෙනස් කරන්න වෙනවා.

මෙන්න මේකට තමයි ORMs කියන සංකල්පය ආවේ. ORM එකක් කියන්නේ programming භාෂාවක (අපේ case එකේ Python) තියෙන objects සහ relational database එකක තියෙන tables අතර mapping එකක් හදන tool එකක්. සරලව කිව්වොත්, database එකේ තියෙන tables අපේ Python objects විදියට represent කරන්න ORM එක අපිට උදව් කරනවා. මේකෙන් වෙන ප්‍රධානම වාසිය තමයි අපිට SQL queries ලියන්න ඕනේ නැති වෙන එක. අපිට පුළුවන් Python code වලින්ම database operations කරන්න. ORM එක අභ්‍යන්තරව (internally) ඒ Python code SQL query බවට translate කරනවා.

ORMs වල වාසි:

  • Abstraction: අපිට database එකේ විස්තර (උදා: SQL dialect) ගැන වැඩිය හිතන්න ඕනේ නැහැ.
  • Productivity: SQL queries ලියන එකට වඩා Python objects එක්ක වැඩ කරන එක පහසුයි සහ වේගවත්.
  • Maintainability: Code එක කියවන්න සහ maintain කරන්න පහසුයි.
  • Database Agnostic: අපි පාවිච්චි කරන database එක මාරු කළොත් (උදා: SQLite ඉඳන් PostgreSQL වලට), ගොඩක් වෙලාවට අපේ ORM code එක වෙනස් කරන්න ඕනේ නැහැ. ORM එකට පුළුවන් ඒකට අවශ්‍ය SQL generate කරන්න.
  • Type Safety: Python objects පාවිච්චි කරන නිසා data types ගැන වැරදීම් අඩු වෙනවා.

Python වල SQLAlchemy කියන්නේ බලගතුම සහ ජනප්‍රියම ORM එකක්. එයාව Flask එක්ක පාවිච්චි කරන්න තමයි Flask-SQLAlchemy extension එක හදලා තියෙන්නේ.

SQLAlchemy සහ SQLite එක්ක වැඩ කරමු

අපි මේ tutorial එකට database එක විදියට SQLite පාවිච්චි කරනවා. SQLite කියන්නේ lightweight, serverless database එකක්. ඒ කියන්නේ ඒක වෙනම server එකක install කරන්න ඕනේ නැහැ. ඒක අපේ ඇප්ලිකේෂන් එකේ file එකක් විදියට තියාගන්න පුළුවන්. ඒක development වලට සහ පොඩි project වලට ගොඩක් හොඳයි.

අවශ්‍ය Modules Install කරගමු:

මුලින්ම, අපිට Flask සහ Flask-SQLAlchemy install කරගන්න ඕනේ. ඔබේ project folder එකේ virtual environment එකක් activate කරගෙන මේ command එක execute කරන්න:

pip install Flask Flask-SQLAlchemy

Flask Application එක Set Up කරමු:

දැන් අපි Flask app එක හදමු සහ SQLAlchemy database instance එකක් initialize කරමු. ඔබේ project root folder එකේ app.py කියලා file එකක් හදලා මේ code එක එකතු කරන්න:

# app.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os

app = Flask(__name__)

# Database Configuration
# SQLite database file path. os.path.abspath(os.getcwd()) gets the current working directory.
# 'sqlite:///site.db' means a SQLite database file named 'site.db' will be created in the current directory.
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # To suppress a warning

db = SQLAlchemy(app) # Initialize SQLAlchemy with the Flask app

# A simple route to check if the app is running
@app.route('/')
def home():
    return '<h1>Welcome to Flask with SQLAlchemy!</h1>'

if __name__ == '__main__':
    # This line ensures that all defined database models (tables) are created in the database
    # before the application starts.
    with app.app_context():
        db.create_all() 
    app.run(debug=True)

මේ app.py එකේ අපි SQLALCHEMY_DATABASE_URI එක 'sqlite:///site.db' කියලා set කරලා තියෙනවා. ඒ කියන්නේ site.db කියන නමින් SQLite database file එකක් අපේ project එකේ root directory එකේ හැදෙනවා. SQLALCHEMY_TRACK_MODIFICATIONS = False දැම්මේ ඒ ගැන warning එකක් එන එක නවත්තන්නයි. db = SQLAlchemy(app) කියන line එකෙන් Flask-SQLAlchemy extension එක Flask app එකත් එක්ක connect කරනවා.

if __name__ == '__main__': block එක ඇතුළේ with app.app_context(): db.create_all() කියන එක ගොඩක් වැදගත්. මේකෙන් කරන්නේ අපේ Python code එකේ අපි define කරන database models (tables) database එක ඇතුළේ automate විදියට හදන එකයි. app.app_context() කියන එක අවශ්‍ය වෙන්නේ Flask extensions වලට Flask application context එක අවශ්‍ය වෙන නිසයි.

Database Model එකක් Define කරමු

දැන් අපි අපේ database table එකට අනුරූප වෙන Python class එකක් හදමු. මේක තමයි SQLAlchemy model එක. මේ model එකෙන් database table එකක තියෙන columns, data types, relationships වගේ දේවල් define කරනවා. අපි User කියලා සරල model එකක් හදමු.

# app.py (continue from previous code)

# Define the User model
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True) # Primary Key, auto-incrementing integer
    username = db.Column(db.String(80), unique=True, nullable=False) # String with max length 80, must be unique and not null
    email = db.Column(db.String(120), unique=True, nullable=False) # String with max length 120, must be unique and not null

    # This method is for representation purposes, useful for debugging
    def __repr__(self):
        return f'<User {self.username}>'

# ... (rest of the Flask app setup code)

if __name__ == '__main__':
    with app.app_context():
        db.create_all() 
    app.run(debug=True)

මේ User class එක db.Model එකෙන් inherit කරනවා. මේකෙන් තමයි SQLAlchemy ට මේක database model එකක් කියලා තේරෙන්නේ.

  • db.Column(): මේකෙන් database table එකේ column එකක් define කරනවා.
  • db.Integer, db.String: මේවා SQLAlchemy data types. මේවා database එකේ තියෙන data types වලට අනුරූප වෙනවා. db.String එකට maximum length එකක් (e.g., 80) දෙන්න පුළුවන්.
  • primary_key=True: මේකෙන් කියන්නේ මේ column එක table එකේ Primary Key එක කියලා. Primary Keys unique වෙනවා වගේම auto-increment වෙනවා (Integer types වලට).
  • unique=True: මේ column එකේ තියෙන හැම value එකක්ම unique වෙන්න ඕනේ කියලා. (එකම username එක දෙපාරක් save කරන්න බැහැ.)
  • nullable=False: මේ column එකට value එකක් අනිවාර්යයෙන්ම දෙන්න ඕනේ කියලා. (NULL වෙන්න බැහැ.)
  • __repr__(self): මේ method එකෙන් වෙන්නේ අපි User object එකක් print කරනකොට ඒක කොහොමද console එකේ පෙන්වන්න ඕනේ කියලා define කරන එක. Debugging වලට මේක ගොඩක් ප්‍රයෝජනවත්.

ඔබ app.py file එක run කරනකොට (python app.py) db.create_all() කියන line එක execute වෙලා site.db file එක ඇතුළේ user කියන table එක හැදෙයි.

CRUD Operations: දත්ත එකතු කිරීම, ලබා ගැනීම, යාවත්කාලීන කිරීම සහ මකා දැමීම

දැන් අපි බලමු මේ database model එක පාවිච්චි කරලා කොහොමද users ලව database එකට එකතු කරන්නේ, ගන්නෙ, update කරන්නේ සහ delete කරන්නේ කියලා. අපි මේවා වෙනම functions ඇතුළේ හදලා, Flask routes පාවිච්චි කරලා මේවා call කරමු.

1. Create (දත්ත එකතු කිරීම - Add New User)

අලුත් user කෙනෙක්ව database එකට එකතු කරන්න, අපි User model එකේ instance එකක් හදලා, ඒක database session එකට add කරලා, commit කරන්න ඕනේ. Database session එක කියන්නේ database එක්ක කරන transactions වල තාවකාලික ගබඩාවක් වගේ දෙයක්.

# app.py (add this route)

from flask import request, jsonify # Import request and jsonify

# ... (rest of the code: imports, app, db, User model)

@app.route('/add_user', methods=['POST'])
def add_user():
    username = request.json.get('username')
    email = request.json.get('email')

    if not username or not email:
        return jsonify({'message': 'Username and Email are required!'}), 400

    new_user = User(username=username, email=email)
    
    try:
        db.session.add(new_user) # Add the new user object to the session
        db.session.commit()      # Commit the changes to the database
        return jsonify({'message': f'User {username} added successfully!'}), 201
    except Exception as e:
        db.session.rollback() # Rollback in case of error (e.g., unique constraint violation)
        return jsonify({'message': f'Error adding user: {str(e)}'}), 500

මේ route එකට POST request එකක් යවලා (උදා: Postman හෝ Insomnia වගේ client එකකින්) JSON payload එකකින් username සහ email යවන්න පුළුවන්. ඒවා අරගෙන අපි අලුත් User object එකක් හදනවා. ඊට පස්සේ db.session.add() වලින් ඒ object එක database session එකට එකතු කරනවා. db.session.commit() කියන එකෙන් තමයි session එකේ තියෙන වෙනස්කම් database එකට ස්ථිරවම save වෙන්නේ. try...except block එක දාන්න ගොඩක් වැදගත්, මොකද username හෝ email unique නැත්නම් error එකක් එන්න පුළුවන්. ඒ වගේ වෙලාවක db.session.rollback() පාවිච්චි කරලා database එක කලින් තිබුණ තත්වෙට ගේන්න පුළුවන්.

2. Read (දත්ත ලබා ගැනීම - Retrieve Users)

Database එකේ තියෙන users ලව ලබා ගන්න SQLAlchemy වලට විවිධ methods තියෙනවා. .query object එක තමයි queries කරන්න පාවිච්චි කරන්නේ.

# app.py (add this route)

# ... (rest of the code)

@app.route('/users', methods=['GET'])
def get_users():
    users = User.query.all() # Get all users from the database
    
    # Convert list of User objects to a list of dictionaries for JSON serialization
    output = []
    for user in users:
        user_data = {'id': user.id, 'username': user.username, 'email': user.email}
        output.append(user_data)
    
    return jsonify({'users': output})

@app.route('/user/<int:user_id>', methods=['GET'])
def get_single_user(user_id):
    user = User.query.get(user_id) # Get user by primary key (id)
    
    if not user:
        return jsonify({'message': 'User not found!'}), 404
    
    user_data = {'id': user.id, 'username': user.username, 'email': user.email}
    return jsonify({'user': user_data})

@app.route('/user_by_username/<string:username>', methods=['GET'])
def get_user_by_username(username):
    # Get user by filtering a specific column (username)
    user = User.query.filter_by(username=username).first() 
    
    if not user:
        return jsonify({'message': 'User not found!'}), 404
    
    user_data = {'id': user.id, 'username': user.username, 'email': user.email}
    return jsonify({'user': user_data})
  • User.query.all(): මේකෙන් database එකේ තියෙන User table එකේ හැම record එකක්ම (සියලුම users ලව) list එකක් විදියට ලබා දෙනවා.
  • User.query.get(user_id): මේකෙන් primary key (id) එක පාවිච්චි කරලා තනි user කෙනෙක්ව ලබා ගන්නවා.
  • User.query.filter_by(username=username).first(): මේකෙන් username column එකෙන් filter කරලා ඊට අදාළව එන පළවෙනි user කෙනෙක්ව ලබා ගන්නවා. (.all() පාවිච්චි කළොත් match වෙන හැමෝම list එකක් විදියට එනවා.)

ලබා ගන්නා User objects කෙලින්ම JSON බවට convert කරන්න බැහැ. ඒ නිසා අපි ඒක dictionary එකක් බවට convert කරලා jsonify කරනවා.

3. Update (දත්ත යාවත්කාලීන කිරීම - Update User)

තියෙන user කෙනෙක්ගේ විස්තර update කරන්න, අපි මුලින්ම ඒ user ව database එකෙන් ලබා අරගෙන, ඔහුගේ attributes (columns) වෙනස් කරලා, db.session.commit() කරන්න ඕනේ.

# app.py (add this route)

# ... (rest of the code)

@app.route('/update_user/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    user = User.query.get(user_id)
    
    if not user:
        return jsonify({'message': 'User not found!'}), 404
    
    username = request.json.get('username')
    email = request.json.get('email')

    if username:
        user.username = username
    if email:
        user.email = email
    
    try:
        db.session.commit() # Commit the changes to the database
        return jsonify({'message': f'User {user.username} updated successfully!'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'Error updating user: {str(e)}'}), 500

මේ update_user route එකට PUT request එකක් යවලා, body එකේ update කරන්න ඕනේ username සහ/හෝ email යවන්න පුළුවන්. අපි මුලින්ම user_id එකෙන් අදාළ user ව ලබා ගන්නවා. ඉන්පසු, ලබා දී ඇති අලුත් values වලින් user object එකේ attributes update කරනවා. අන්තිමට db.session.commit() කරලා වෙනස්කම් database එකට save කරනවා.

4. Delete (දත්ත මකා දැමීම - Delete User)

User කෙනෙක්ව database එකෙන් delete කරන්න, අපි මුලින්ම ඒ user ව database එකෙන් ලබා අරගෙන, ඒක database session එකෙන් delete කරලා, commit කරන්න ඕනේ.

# app.py (add this route)

# ... (rest of the code)

@app.route('/delete_user/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    user = User.query.get(user_id)
    
    if not user:
        return jsonify({'message': 'User not found!'}), 404
    
    try:
        db.session.delete(user) # Delete the user object from the session
        db.session.commit()     # Commit the changes to the database
        return jsonify({'message': f'User {user.username} deleted successfully!'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'Error deleting user: {str(e)}'}), 500

delete_user route එකට DELETE request එකක් යවනවා. මුලින්ම user_id එකෙන් අදාළ user ව ලබා ගන්නවා. ඊට පස්සේ db.session.delete(user) වලින් session එකෙන් user ව අයින් කරනවා. අන්තිමට db.session.commit() කරලා ඒ වෙනස්කම database එකට save කරනවා.

පොදු ගැටළු සහ විසඳුම් (Common Issues & Troubleshooting)

SQLAlchemy එක්ක වැඩ කරනකොට මුලින්ම එන පොදු ගැටළු කිහිපයක් සහ ඒවාට විසඳුම් බලමු:

  • db.create_all() Call නොවීම:ඔබගේ database models define කරලා තිබුණත්, database tables හැදිලා නැත්නම්, බොහෝ වෙලාවට හේතුව db.create_all() function එක call කරලා නැති එක හෝ ඒක app.app_context() ඇතුළේ call කරලා නැති එක වෙන්න පුළුවන්.විසඳුම: if __name__ == '__main__': block එක ඇතුළේ with app.app_context(): db.create_all() කියලා තියෙනවාද කියලා බලන්න.
  • Database Connection String Errors:SQLALCHEMY_DATABASE_URI එක වැරදියට දීලා තිබ්බොත් database එකට connect වෙන්න බැරි වෙනවා.විසඳුම: app.config['SQLALCHEMY_DATABASE_URI'] එකේ value එක හරියට තියෙනවාද කියලා දෙවරක් check කරන්න. sqlite:///site.db කියන්නේ relative path එකක්. absolute path එකක් දෙන්නත් පුළුවන්, උදා: sqlite:////path/to/your/db/site.db.
  • db.session.commit() අමතක වීම:ඔබ දත්ත add කළා, update කළා, හෝ delete කළා. ඒත් database එකේ වෙනසක් පේන්න නැත්නම්, බොහෝ විට db.session.commit() call කරන්න අමතක වෙලා ඇති.විසඳුම: සෑම database operation එකකින් පසුව db.session.commit() call කරන්න අමතක කරන්න එපා. ඔබට transaction එකක් cancel කරන්න අවශ්‍ය නම් db.session.rollback() පාවිච්චි කරන්න.
  • Unique Constraint Violations:unique=True කියලා define කරලා තියෙන column එකකට දැනටමත් database එකේ තියෙන value එකක් දෙන්න හැදුවොත් IntegrityError එකක් එනවා. (අපේ User model එකේ username සහ email).විසඳුම: try...except block එකක් පාවිච්චි කරලා මේ වගේ errors handle කරන්න. error එකක් ආවොත් db.session.rollback() කරන්න. Front-end එකෙන් data submit කරනකොටත් මේ වගේ validations කරන එක හොඳයි.
  • ORM Query Syntax:SQLAlchemy queries වල syntax වැරදීම් වෙන්න පුළුවන්. උදා: filter (condition එකක් String විදියට දෙනවා) වෙනුවට filter_by (keyword arguments වලින් දෙනවා) පාවිච්චි කිරීම.විසඳුම: නිවැරදි syntax එකට අනුකූලව query කරන්න. documentation එක බලන එක හොඳ පුරුද්දක්.

Best Practices සහ අමතර Tips

  • ORM එකක් පාවිච්චි කරන්න:සෑම විටම database එක්ක වැඩ කරන්න ORM එකක් (SQLAlchemy වගේ) පාවිච්චි කරන්න පුරුදු වෙන්න. ඒකෙන් code එක maintainability වැඩි කරනවා වගේම development process එක වේගවත් කරනවා.
  • Database Sessions නිවැරදිව කළමනාකරණය කරන්න:Flask-SQLAlchemy මඟින් request එකක අවසානයේදී session එක automacially remove කරනවා. ඒත්, ඔබ CLI commands (command line interface) හෝ background tasks කරනවා නම්, ඔබ with app.app_context(): block එක ඇතුළේ db.session.remove() හෝ db.session.close() වැනි දේවල් පාවිච්චි කරලා sessions නිවැරදිව close කරන බවට වග බලා ගන්න.
  • Performance Considerations:ලොකු queries හෝ ගොඩක් දත්ත එක්ක වැඩ කරනකොට ORM එකේ performance ගැන හිතන්න වෙනවා. සමහර වෙලාවට raw SQL පාවිච්චි කරන එක වඩා කාර්යක්ෂම වෙන්න පුළුවන්. ඒත්, පොඩි project වලට සහ CRUD operations වලට ORM එක හොඳටම ඇති.

Secrets Management:Production environments වලදී database connection string වගේ sensitive information කෙලින්ම code එකේ දාන්න එපා. එවැනි දේවල් environment variables හෝ configuration files (e.g., .env file) හරහා manage කරන්න.

# Example using environment variable
import os
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or 'sqlite:///site.db'

Database Migrations:Project එකක database schema එක වෙනස් කරන්න අවශ්‍ය වුණාම (උදා: අලුත් column එකක් add කරනවා, column එකක data type එක වෙනස් කරනවා), අතින් database schema වෙනස් කරන එක අවදානම්. ඒකට Flask-Migrate (Alembic මත පදනම් වූ) වැනි migration tools පාවිච්චි කරන්න.

pip install Flask-Migrate

මේකෙන් ඔබට පුළුවන් database changes version control කරන්න. ඒ ගැන වෙනම tutorial එකක් කරන්න පුළුවන්.

නිගමනය (Conclusion)

මේ tutorial එකෙන් අපි Python Flask application එකක් ඇතුළේ databases එක්ක වැඩ කරන්න SQLAlchemy කොහොමද පාවිච්චි කරන්නේ කියලා විස්තරාත්මකව ඉගෙන ගත්තා. අපි ORMs ගැන තියරි දැනුම ලබා ගත්තා, Flask-SQLAlchemy install කරගෙන app එකක් configure කළා, database model එකක් define කළා, සහ users ලව add කරන්න, retrieve කරන්න, update කරන්න, delete කරන්න (CRUD operations) කොහොමද කියලා practical code examples එක්කම බැලුවා.

දැන් ඔබ Flask සහ SQLAlchemy පාවිච්චි කරලා database-driven web applications හදන්න අවශ්‍ය මූලික දැනුම සහ හැකියාව ලබාගෙන ඉවරයි. මේක ඉතාම වැදගත් පියවරක්, මොකද ගොඩක්ම වෙබ් ඇප්ලිකේෂන් වලට database අත්‍යවශ්‍යයි. ඔබට පුළුවන් මේ දැනුම පාවිච්චි කරලා තව complex models හදන්න, relationships (one-to-many, many-to-many) ඉගෙන ගන්න, සහ Flask-Migrate වගේ advanced topics ගැන හොයලා බලන්න.

මේ code එක ඔබේ computer එකේ run කරලා බලන්න, වෙනස්කම් කරලා අත්හදා බලන්න. ඔබට මේ tutorial එක ගැන අදහස්, ප්‍රශ්න හෝ අත්දැකීම් තියෙනවා නම් පහළින් comment කරන්න. අපි ඊළඟ ලිපියකින් හමුවෙමු! සුබ දවසක්!