Executing Raw SQL Queries in Flask-SQLAlchemy Applications

Nov 19, 2025 · Programming · 8 views · 7.8

Keywords: Flask | SQLAlchemy | Raw SQL | Python | Database

Abstract: This article provides a comprehensive guide on executing raw SQL queries in Flask applications using SQLAlchemy. It covers methods such as db.session.execute() with the text() function, parameterized queries for SQL injection prevention, result handling, and best practices. Practical code examples illustrate secure and efficient database operations.

Introduction

In Flask applications that utilize SQLAlchemy for database interactions, the Object-Relational Mapping (ORM) layer offers a convenient way to work with databases using Python objects. However, executing raw SQL queries becomes necessary in scenarios such as complex joins, performance optimizations, or database-specific operations. This article explores methods for executing raw SQL in Flask-SQLAlchemy, emphasizing security, transaction management, and result handling.

Methods for Executing Raw SQL

SQLAlchemy provides multiple approaches for executing raw SQL queries, primarily involving the session object or the engine object. It is recommended to use the session object for better transaction management, ensuring that multiple queries in a single request are handled as a unit to reduce data corruption risks.

A common method is db.session.execute(), which executes queries within the current transaction. Another approach is db.engine.execute(), but this is connectionless and deprecated in SQLAlchemy 2.0, so it should be avoided in new code.

Using the text() Function

To execute raw SQL safely, SQLAlchemy provides the text() function from the sqlalchemy module. This function wraps the SQL string and enables parameter binding, which helps prevent SQL injection attacks.

Example:

from sqlalchemy import text

sql = text('SELECT * FROM users WHERE email = :email')
result = db.session.execute(sql, {'email': 'user@example.com'})

In this example, the :email parameter is bound to a value, making the query secure.

Parameterized Queries and SQL Injection Prevention

Using parameterized queries is essential for security. Instead of concatenating strings, always use placeholders like :param and pass a dictionary of values. This prevents malicious inputs from being executed as SQL code.

For instance, avoid:

query = "SELECT * FROM users WHERE email = '" + email + "'"  # Vulnerable to SQL injection

Instead, use:

query = text('SELECT * FROM users WHERE email = :email')
result = db.session.execute(query, {'email': email})

Handling Query Results

When a query is executed, it returns a result object that can be iterated over. Each row can be accessed using index or column names.

Example:

for row in result:
    print(row[0])  # Access by index
    print(row['email'])  # Access by column name

Alternatively, you can convert the result to a list of dictionaries or named tuples for easier handling.

from collections import namedtuple

Record = namedtuple('Record', result.keys())
records = [Record(*r) for r in result.fetchall()]
for record in records:
    print(record.email)

Practical Examples

Consider a complete example within a Flask app context.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

with app.app_context():
    # Create a table
    db.session.execute(text('''
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY,
            name TEXT,
            email TEXT
        )
    '''))
    db.session.commit()

    # Insert data
    db.session.execute(text('INSERT INTO users (name, email) VALUES (:name, :email)'), 
                      {'name': 'John Doe', 'email': 'john@example.com'})
    db.session.commit()

    # Query data
    result = db.session.execute(text('SELECT * FROM users'))
    for row in result:
        print(f"ID: {row.id}, Name: {row.name}, Email: {row.email}")

This example demonstrates table creation, data insertion, and querying within a Flask app context.

Best Practices

Always use the session object for executing queries to ensure proper transaction management. Prefer parameterized queries with the text() function to avoid SQL injection. Handle exceptions and commit changes appropriately. In Flask, use the application context to manage database connections.

For complex queries involving multiple joins or inline views, raw SQL may be more efficient, but ensure it is written securely and tested thoroughly.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.