Advanced Flask Patterns and Best Practices

Advanced Flask Patterns and Best Practices

When developing a Flask application, the structure of your project can significantly influence both development speed and maintainability. Using Blueprints and packages is a powerful method to organize your application into manageable modules, promoting a clean separation of concerns.

Blueprints are a feature in Flask that allows you to organize your application into distinct components. Each blueprint can contain its own views, static files, and templates, making it easier to modularize your application. That’s particularly useful in larger applications where functionality can be divided into multiple sections.

To create a blueprint, you start by instantiating a Blueprint object, followed by defining routes and views. Here’s a simple example:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask import Blueprint, render_template
# Create a blueprint
mod_auth = Blueprint('auth', __name__)
@mod_auth.route('/login')
def login():
return render_template('login.html')
@mod_auth.route('/logout')
def logout():
return "Logged out successfully!"
from flask import Blueprint, render_template # Create a blueprint mod_auth = Blueprint('auth', __name__) @mod_auth.route('/login') def login(): return render_template('login.html') @mod_auth.route('/logout') def logout(): return "Logged out successfully!"
from flask import Blueprint, render_template

# Create a blueprint
mod_auth = Blueprint('auth', __name__)

@mod_auth.route('/login')
def login():
    return render_template('login.html')

@mod_auth.route('/logout')
def logout():
    return "Logged out successfully!"

Once defined, you can register the blueprint in your Flask application instance, allowing the routes defined in the blueprint to be accessible:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask import Flask
app = Flask(__name__)
# Register the blueprint
app.register_blueprint(mod_auth, url_prefix='/auth')
from flask import Flask app = Flask(__name__) # Register the blueprint app.register_blueprint(mod_auth, url_prefix='/auth')
from flask import Flask

app = Flask(__name__)

# Register the blueprint
app.register_blueprint(mod_auth, url_prefix='/auth')

This structure not only keeps your code organized but also allows for easy expansion. You can create additional blueprints for other parts of your application, such as an admin dashboard or user profiles, keeping your routes clean and manageable.

Packages offer another layer of organization. By grouping related modules into packages, you can encapsulate functionality that can be reused across your application. A package in Python is simply a directory containing an __init__.py file, which makes it a module that can be imported. Here’s how you might structure a simple package:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
my_flask_app/
├── app/
│ ├── __init__.py
│ ├── views.py
│ ├── models.py
│ └── auth/
│ ├── __init__.py
│ ├── views.py
│ └── forms.py
└── run.py
my_flask_app/ ├── app/ │ ├── __init__.py │ ├── views.py │ ├── models.py │ └── auth/ │ ├── __init__.py │ ├── views.py │ └── forms.py └── run.py
my_flask_app/
    ├── app/
    │   ├── __init__.py
    │   ├── views.py
    │   ├── models.py
    │   └── auth/
    │       ├── __init__.py
    │       ├── views.py
    │       └── forms.py
    └── run.py

In this structure, the main application logic resides in the app package, while the auth sub-package encapsulates all authentication-related functionality, including views and forms. This modular approach not only enhances code readability but also simplifies the testing and debugging process.

Managing Configuration and Environment Variables

When it comes to managing configuration and environment variables in Flask, you are essentially setting the stage for how your application behaves in different environments—development, testing, and production. Flask provides a robust way to handle configuration settings, ensuring that your application can adapt to various scenarios without requiring code changes.

Flask applications can be configured in several ways, including using a configuration file, environment variables, or directly within the application code. Each method has its own advantages and is suited for different use cases.

One common practice is to use a configuration file, usually in Python or JSON format. This allows you to organize all your settings in one location. You can create a dedicated config.py file to store your configuration settings:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# config.py
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
DEBUG = os.environ.get('FLASK_DEBUG', 'False') == 'True'
DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
# config.py import os class Config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess' DEBUG = os.environ.get('FLASK_DEBUG', 'False') == 'True' DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
 
# config.py

import os

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
    DEBUG = os.environ.get('FLASK_DEBUG', 'False') == 'True'
    DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'

In this example, we define a Config class that pulls values from environment variables using the os.environ.get() method. This approach is beneficial because it allows sensitive information, such as API keys or database URLs, to be managed outside the source code, enhancing security.

To apply this configuration to your Flask application, you can load it at the application startup:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# app/__init__.py
from flask import Flask
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
# app/__init__.py from flask import Flask from config import Config app = Flask(__name__) app.config.from_object(Config)
 
# app/__init__.py

from flask import Flask
from config import Config

app = Flask(__name__)
app.config.from_object(Config)

By calling app.config.from_object(Config), you import all the settings defined in your Config class into your Flask application. This method leverages the power of object-oriented programming, which will allow you to create multiple configuration classes for different environments, such as DevelopmentConfig, TestingConfig, and ProductionConfig, each inheriting from the base Config class.

Another widely used approach for managing configuration is through environment variables. That is particularly useful in deployment scenarios, where you want to keep sensitive information out of your codebase. You can set environment variables on your server or use a .env file with the help of libraries like python-dotenv. Here’s how you might use it:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# .env
SECRET_KEY=your_secret_key
FLASK_DEBUG=True
DATABASE_URL=postgresql://user:password@localhost/dbname
# .env SECRET_KEY=your_secret_key FLASK_DEBUG=True DATABASE_URL=postgresql://user:password@localhost/dbname
 
# .env

SECRET_KEY=your_secret_key
FLASK_DEBUG=True
DATABASE_URL=postgresql://user:password@localhost/dbname

After installing python-dotenv, you can load these environment variables at the start of your application:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# app/__init__.py
from flask import Flask
from dotenv import load_dotenv
import os
load_dotenv() # Load environment variables from .env file
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['DEBUG'] = os.getenv('FLASK_DEBUG', 'False') == 'True'
app.config['DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')
# app/__init__.py from flask import Flask from dotenv import load_dotenv import os load_dotenv() # Load environment variables from .env file app = Flask(__name__) app.config['SECRET_KEY'] = os.getenv('SECRET_KEY') app.config['DEBUG'] = os.getenv('FLASK_DEBUG', 'False') == 'True' app.config['DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')
 
# app/__init__.py

from flask import Flask
from dotenv import load_dotenv
import os

load_dotenv()  # Load environment variables from .env file

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['DEBUG'] = os.getenv('FLASK_DEBUG', 'False') == 'True'
app.config['DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')

Using environment variables not only keeps your configuration flexible but also aligns well with the Twelve-Factor App methodology, which emphasizes strict separation of config from code.

Implementing Authentication and Authorization

Implementing authentication and authorization in a Flask application is paramount for securing your resources and managing user access. Flask provides several extensions to facilitate this process, with Flask-Login being one of the most popular. It handles session management, so that you can manage user sessions easily.

To get started with Flask-Login, you first need to install it. You can do this using pip:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pip install flask-login
pip install flask-login
pip install flask-login

Next, you need to set up a user model and configure Flask-Login. Here’s an example of how to create a simple user model and set up Flask-Login:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask import Flask
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
app = Flask(__name__)
app.secret_key = 'your_secret_key' # Important for session management
login_manager = LoginManager()
login_manager.init_app(app)
# User model
class User(UserMixin):
def __init__(self, id):
self.id = id
# Dummy user store
users = {'user@example.com': {'password': 'password'}}
@login_manager.user_loader
def load_user(user_id):
return User(user_id)
@app.route('/login', methods=['GET', 'POST'])
def login():
email = 'user@example.com' # Assume this comes from a form submission
password = 'password' # Assume this comes from a form submission
user = users.get(email)
if user and user['password'] == password:
user = User(email)
login_user(user)
return 'Logged in successfully!'
return 'Invalid credentials'
@app.route('/logout')
@login_required
def logout():
logout_user()
return 'Logged out successfully!'
@app.route('/protected')
@login_required
def protected():
return f'Logged in as: {current_user.id}'
from flask import Flask from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user app = Flask(__name__) app.secret_key = 'your_secret_key' # Important for session management login_manager = LoginManager() login_manager.init_app(app) # User model class User(UserMixin): def __init__(self, id): self.id = id # Dummy user store users = {'user@example.com': {'password': 'password'}} @login_manager.user_loader def load_user(user_id): return User(user_id) @app.route('/login', methods=['GET', 'POST']) def login(): email = 'user@example.com' # Assume this comes from a form submission password = 'password' # Assume this comes from a form submission user = users.get(email) if user and user['password'] == password: user = User(email) login_user(user) return 'Logged in successfully!' return 'Invalid credentials' @app.route('/logout') @login_required def logout(): logout_user() return 'Logged out successfully!' @app.route('/protected') @login_required def protected(): return f'Logged in as: {current_user.id}'
from flask import Flask
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user

app = Flask(__name__)
app.secret_key = 'your_secret_key'  # Important for session management
login_manager = LoginManager()
login_manager.init_app(app)

# User model
class User(UserMixin):
    def __init__(self, id):
        self.id = id

# Dummy user store
users = {'user@example.com': {'password': 'password'}}

@login_manager.user_loader
def load_user(user_id):
    return User(user_id)

@app.route('/login', methods=['GET', 'POST'])
def login():
    email = 'user@example.com'  # Assume this comes from a form submission
    password = 'password'  # Assume this comes from a form submission
    user = users.get(email)
    if user and user['password'] == password:
        user = User(email)
        login_user(user)
        return 'Logged in successfully!'
    return 'Invalid credentials'

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return 'Logged out successfully!'

@app.route('/protected')
@login_required
def protected():
    return f'Logged in as: {current_user.id}'

In this example, we define a simple User class that inherits from UserMixin, which provides the necessary methods for Flask-Login. We also use a dummy dictionary to simulate a user database. In a real application, you would typically retrieve user data from a database.

Setting up routes for login, logout, and protected content is simpler. The login_required decorator ensures that only authenticated users can access certain routes. If an unauthenticated user attempts to access a protected route, they will be redirected to the login page.

Authorization is about determining what authenticated users can do within your application. You can implement role-based access control (RBAC) by creating roles and permissions for users. This can be done using a combination of Flask-Login and a simple permission-checking mechanism. For example:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask_login import current_user
# Define roles
roles = {
'admin': ['can_view', 'can_edit', 'can_delete'],
'user': ['can_view']
}
def has_permission(permission):
if current_user.is_authenticated:
user_role = 'admin' # This should be dynamically set based on the user's role
return permission in roles.get(user_role, [])
return False
@app.route('/edit')
@login_required
def edit():
if not has_permission('can_edit'):
return 'You do not have permission to edit this resource.'
return 'You can edit this resource!'
from flask_login import current_user # Define roles roles = { 'admin': ['can_view', 'can_edit', 'can_delete'], 'user': ['can_view'] } def has_permission(permission): if current_user.is_authenticated: user_role = 'admin' # This should be dynamically set based on the user's role return permission in roles.get(user_role, []) return False @app.route('/edit') @login_required def edit(): if not has_permission('can_edit'): return 'You do not have permission to edit this resource.' return 'You can edit this resource!'
from flask_login import current_user

# Define roles
roles = {
    'admin': ['can_view', 'can_edit', 'can_delete'],
    'user': ['can_view']
}

def has_permission(permission):
    if current_user.is_authenticated:
        user_role = 'admin'  # This should be dynamically set based on the user's role
        return permission in roles.get(user_role, [])
    return False

@app.route('/edit')
@login_required
def edit():
    if not has_permission('can_edit'):
        return 'You do not have permission to edit this resource.'
    return 'You can edit this resource!'

In this code snippet, the has_permission function checks if the current user has the required permissions based on their role. This approach can be expanded further by integrating a more complex permission management system as your application grows.

Optimizing Database Interactions with SQLAlchemy

When it comes to optimizing database interactions in Flask applications, SQLAlchemy stands out as a powerful ORM (Object Relational Mapper). It enables developers to interact with the database using Python objects rather than writing raw SQL queries, thereby enhancing productivity and maintainability. Using SQLAlchemy effectively can lead to significant improvements in performance, especially as your application scales.

To begin optimizing your database interactions, it’s crucial to establish a proper relationship between your models and the database schema. SQLAlchemy allows you to define relationships easily using its declarative base. Here’s an example of how to define a simple model for a blog application:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) posts = db.relationship('Post', backref='author', lazy=True) class Post(db.Model): __tablename__ = 'posts' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(120), nullable=False) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), nullable=False)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)

In this setup, we have two models: User and Post. The db.relationship() function establishes a one-to-many relationship between users and their posts. This allows you to easily access a user’s posts through the author back-reference.

One of the key performance optimizations in SQLAlchemy is using the lazy loading strategy effectively. By default, SQLAlchemy uses select style loading, which means it will fetch related objects in a separate query. However, for certain cases, using joined or subquery loading can reduce the number of queries made, thus improving performance. Here’s how you can adjust the loading strategy:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
posts = db.relationship('Post', backref='author', lazy='joined') # Using joined loading
class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) posts = db.relationship('Post', backref='author', lazy='joined') # Using joined loading
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    posts = db.relationship('Post', backref='author', lazy='joined')  # Using joined loading

In this modified model, all related posts for a user will be loaded in the same query. This can be particularly beneficial when displaying user data along with their posts, as it minimizes the number of database round trips.

Another optimization technique involves using bulk operations when inserting or updating data. Instead of adding each object to the session and committing, you can use the bulk_save_objects method for bulk inserts, which is significantly faster:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
users = [User(username=f'user{i}') for i in range(1000)]
db.session.bulk_save_objects(users)
db.session.commit()
users = [User(username=f'user{i}') for i in range(1000)] db.session.bulk_save_objects(users) db.session.commit()
users = [User(username=f'user{i}') for i in range(1000)]
db.session.bulk_save_objects(users)
db.session.commit()

This approach can drastically reduce the overhead associated with committing multiple changes to the database.

Additionally, indexing plays a pivotal role in optimizing query performance. By defining indexes on frequently queried fields, you can speed up data retrieval significantly. Here’s how to add an index to the username field:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False, index=True) # Adding an index
class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False, index=True) # Adding an index
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False, index=True)  # Adding an index

When designing your application, consider how data will be queried and optimize your models accordingly. Using the right indexes can lead to dramatic improvements in query performance, especially with larger datasets.

Finally, employing connection pooling can also enhance performance. SQLAlchemy provides built-in support for connection pooling, which allows the application to reuse database connections rather than opening a new one for every request. You can configure the connection pool size in your application setup:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
app.config['SQLALCHEMY_POOL_SIZE'] = 10 # Set the desired pool size
app.config['SQLALCHEMY_POOL_SIZE'] = 10 # Set the desired pool size
app.config['SQLALCHEMY_POOL_SIZE'] = 10  # Set the desired pool size

Testing and Debugging Flask Applications

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# Testing in Flask can often feel like an afterthought, but it's a critical aspect of the development process.
# Using the built-in testing capabilities of Flask, you can create robust tests that ensure your application behaves as expected.
from flask import Flask, jsonify
import unittest
app = Flask(__name__)
@app.route('/api/data', methods=['GET'])
def get_data():
return jsonify({'key': 'value'})
class FlaskAppTestCase(unittest.TestCase):
def setUp(self):
# Create a test client for the Flask application
self.app = app.test_client()
self.app.testing = True # Enable testing mode
def test_get_data(self):
# Use the test client to make a request to the API
response = self.app.get('/api/data')
# Assert the response is 200 OK
self.assertEqual(response.status_code, 200)
# Assert the response data
self.assertEqual(response.json, {'key': 'value'})
if __name__ == '__main__':
unittest.main()
# Testing in Flask can often feel like an afterthought, but it's a critical aspect of the development process. # Using the built-in testing capabilities of Flask, you can create robust tests that ensure your application behaves as expected. from flask import Flask, jsonify import unittest app = Flask(__name__) @app.route('/api/data', methods=['GET']) def get_data(): return jsonify({'key': 'value'}) class FlaskAppTestCase(unittest.TestCase): def setUp(self): # Create a test client for the Flask application self.app = app.test_client() self.app.testing = True # Enable testing mode def test_get_data(self): # Use the test client to make a request to the API response = self.app.get('/api/data') # Assert the response is 200 OK self.assertEqual(response.status_code, 200) # Assert the response data self.assertEqual(response.json, {'key': 'value'}) if __name__ == '__main__': unittest.main()
# Testing in Flask can often feel like an afterthought, but it's a critical aspect of the development process. 
# Using the built-in testing capabilities of Flask, you can create robust tests that ensure your application behaves as expected.

from flask import Flask, jsonify
import unittest

app = Flask(__name__)

@app.route('/api/data', methods=['GET'])
def get_data():
    return jsonify({'key': 'value'})

class FlaskAppTestCase(unittest.TestCase):
    def setUp(self):
        # Create a test client for the Flask application
        self.app = app.test_client()
        self.app.testing = True  # Enable testing mode

    def test_get_data(self):
        # Use the test client to make a request to the API
        response = self.app.get('/api/data')
        # Assert the response is 200 OK
        self.assertEqual(response.status_code, 200)
        # Assert the response data
        self.assertEqual(response.json, {'key': 'value'})

if __name__ == '__main__':
    unittest.main()

Flask’s testing capabilities are built around the concept of a test client, which allows you to simulate requests to your application without needing to spin up a server. This is invaluable for writing unit tests, as it allows you to check the functionality of various routes, responses, and even error handling.

To get started, import the necessary modules and create a test case that subclasses unittest.TestCase. Within this test case, you can define a setUp method that initializes the test client and any application context needed for your tests.

In the example provided, we define a simple Flask application with a single route that returns JSON data. The test_get_data method uses the test client to send a GET request to the /api/data endpoint and checks the response’s status code and JSON content. This structure allows you to easily add more tests for different endpoints and functionalities.

For more complex applications, you might want to test the database interactions as well. Flask provides the capability to work with test databases, so that you can perform operations without affecting your production data. You can achieve this by setting up a separate testing database and using transactions to rollback changes after each test.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask_sqlalchemy import SQLAlchemy<p></p>
<p># Initialize SQLAlchemy<br>
db = SQLAlchemy(app)</p>
<p>class TestDatabaseSetup(unittest.TestCase):<br>
def setUp(self):<br>
# Configure the test database<br>
self.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'<br>
db.create_all() # Create database tables</p>
<p> def tearDown(self):<br>
db.session.remove() # Clean up the session<br>
db.drop_all() # Drop database tables</p>
<p> def test_user_creation(self):<br>
user = User(username='testuser')<br>
db.session.add(user)<br>
db.session.commit()</p>
from flask_sqlalchemy import SQLAlchemy<p></p> <p># Initialize SQLAlchemy<br> db = SQLAlchemy(app)</p> <p>class TestDatabaseSetup(unittest.TestCase):<br> def setUp(self):<br> # Configure the test database<br> self.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'<br> db.create_all() # Create database tables</p> <p> def tearDown(self):<br> db.session.remove() # Clean up the session<br> db.drop_all() # Drop database tables</p> <p> def test_user_creation(self):<br> user = User(username='testuser')<br> db.session.add(user)<br> db.session.commit()</p>
from flask_sqlalchemy import SQLAlchemy

# Initialize SQLAlchemy
db = SQLAlchemy(app)

class TestDatabaseSetup(unittest.TestCase):
def setUp(self):
# Configure the test database
self.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
db.create_all() # Create database tables

def tearDown(self):
db.session.remove() # Clean up the session
db.drop_all() # Drop database tables

def test_user_creation(self):
user = User(username='testuser')
db.session.add(user)
db.session.commit()

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *