Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building Scalable Web Applications with Flask

Tech 1

Establish a standard directory layout to separate static assets, templates, and application logic. A typical organization includes:

  • static/: Stores CSS, JS, and image files.
  • templates/: Holds HTML templates processed by Jinja2.
  • app.py: The main entry point for the WSGI application.
  • modules/: Additional Python modules for scalability.

Application Factory Pattern

Instantiate the application object using the factory pattern to support blueprints and extensions.

from flask import Flask

def create_app(config_name='default'):
    app = Flask(__name__)
    app.config.from_object(factories.{config_name})
    return app

if __name__ == '__main__':
    web_app = create_app()
    web_app.run(host='0.0.0.0', debug=True)

Request Routing and Methods

Define routes to handle HTTP requests. Specify allowed methods explicitly to enforce protocol correctness.

@app.route('/data/extract/<int:item_id>', methods=['GET', 'POST'])
def get_data(item_id):
    if request.method == 'POST':
        # Handle form submission
        pass
    elif item_id < 0:
        abort(400)
    return {'id': item_id}

Query parameters can be retrieved when path arguments are not sufficient:

@app.route('/search/')
def search_query():
    keyword = request.args.get('q')
    limit = request.args.get('limit', 10)
    return render_search(keyword, limit)

URL generation is handled programmatically to avoid hardcoding paths:

redirect_url = url_for('static', filename='logo.png')
avail_path = url_for('home_page', page=2)

Configuration Management

Settings should be externalized from code. Use environment variables or distinct configuration classes.

# config.py
class Config:
    DEBUG = True
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')

To apply settings in the main instance:

app.config['JSON_AS_ASCII'] = False

Or load from an object:

app.config.from_object(Config)

Response Handling

Return JSON responses directly using the provided utilities:

from flask import jsonify

def api_response(data, status_code=200):
    return jsonify(data), status_code

Templating with Jinja2

Templates allow separation of logic and presentation. Variables passed from view are rendered using double curly braces.

return render_template('layout.html', title='Home', user={'name': 'Alice'})

Inside index.html:

<h1>Hello {{ user.name }}</h1>
<p>Age: {{ user.age|default(18) }}</p>

Filters and Control Flow

Built-in filters modify output dynamically:

<!-- Length filter -->
{{ content|length }}

<!-- Math operations -->
{% set total = items|map(attribute='price')|sum %}

<!-- Looping -->
{% for post in posts %}
    <div>{{ post.title }}</div>
{% endfor %}

Inheritance reduces duplication in layout structures:

<!-- base.html -->
{% block head %}<style>body { font-family: sans-serif; }</style>{% endblock %}
<body>{% block body %}{% endblock %}</body>

<!-- child.html -->
{% extends "base.html" %}
{% block body %}<h1>Welcome</h1>{% endblock %}

Modular Design with Blueprints

Large applications split functionality into registered blueprints. This isolates URL prefixes and resources.

# module_auth.py
from flask import Blueprint
auth_bp = Blueprint('auth', __name__, url_prefix='/auth')

@auth_bp.route('/login')
def login_form():
    return "Login Page"

# app.py
from module_auth import auth_bp
app.register_blueprint(auth_bp)

Database Integration (SQLAlchemy)

The SQLAlchemy ORM abstracts database interactions. Define models inheriting from db.Model.

class Author(db.Model):
    __tablename__ = 'authors'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True)
    posts = db.relationship('Post', backref='writer', lazy='dynamic')

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    author_id = db.Column(db.Integer, db.ForeignKey('authors.id'))
    content = db.Column(db.Text)

Performing CRUD operations involves session management:

new_book = Book(title='New Release', price=19.99)
db.session.add(new_book)
db.session.commit()

# Querying
book_instance = Book.query.filter_by(price=19.99).first()

# Updates
book_instance.content = 'Updated Content'
db.session.commit()

# Deletion
Book.query.filter_by(id=1).delete()
db.session.commit()

State Management

Cookies are stored on the client, while sessions reside server-side but require a secret key.

# Cookies
response = make_response("Cookie Set")
response.set_cookie('session_token', token_value, max_age=3600)

# Session Access
username = request.cookies.get('session_token')

# Server-side Sessions
app.config['SECRET_KEY'] = 'super_secure_key'
session['user_id'] = 101
retrieved_id = session.get('user_id')

Form Validation

Use WTForms to validate input before processing business logic.

# forms.py
class RegistrationForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[Length(min=6)])
    submit = SubmitField('Submit')

Process in the view:

form = RegistrationForm(
    formdata=request.form,
    obj=current_user
)
if form.validate_on_submit():
    # Process valid data
    pass
else:
    return form.errors

Security Best Practices

Never store plain-text passwords. Hash credentials using Werkzeug.

from werkzeug.security import generate_password_hash, check_password_hash

hashed_pw = generate_password_hash('clear_text_password')
is_valid = check_password_hash(hashed_pw, 'clear_text_password')

Generate verification codes programmatically:

import random, string
letters = string.ascii_letters + string.digits
code = ''.join(random.sample(letters, 6))

External Services Integration

Mailing

Configure SMTP settings externally and send via flask-mail.

mail.send(Message('Subject', recipients=['user@example.com'], html='<p>Body</p>'))

CORS Support

Allow cross-origin requests when serving APIs to frontends hosted elsewhere.

from flask_cors import CORS
CORS(app, resources={r"/*": {"origins": "*"}})

Alternatively, set headers manually on responses:

response = jsonify({'status': 'ok'})
response.headers['Access-Control-Allow-Origin'] = '*'

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.