From 0 to 1: Flask Project Development Process and Best Practices

I. What is Flask?

Flask is a lightweight Python Web framework that implements the core functionality of web applications with concise code while maintaining high flexibility. Unlike Django’s “batteries-included” philosophy, Flask is more like a “toolkit” where you can choose components (such as ORM, form handling, etc.) as needed. It is ideal for beginners to start web development and also suitable for quickly developing small-to-medium projects.

II. Development Environment Setup

1. Install Python

First, ensure Python (version 3.7+ is recommended) is installed on your computer:
- Check Installation: Open the terminal/command line and run python --version or python3 --version. If the version number is displayed, the installation is successful.
- Download Link: Python Official Website

2. Install Flask

Use Python’s package manager pip to install Flask:

pip install flask

Verify the installation: Open the Python interactive environment (python or python3) and run import flask. No error messages indicate a successful installation.

III. Project Development Process

1. Create a Virtual Environment (MANDATORY!)

To avoid dependency conflicts between different projects, it is recommended to create an independent virtual environment for each project:
- Create a Virtual Environment (Python 3.3+ has the built-in venv module):

  python -m venv myflaskenv  # Works on Windows/Linux/Mac
  • Activate the Virtual Environment:
  • Windows (Command Prompt): myflaskenv\Scripts\activate
  • Linux/Mac (Terminal): source myflaskenv/bin/activate
    After activation, the terminal prefix will show (myflaskenv), indicating the environment is active.

2. Initialize Project Structure

A good project structure makes code easier to maintain. The recommended basic structure is:

myflaskapp/          # Project root directory
├── app.py           # Application entry point
├── requirements.txt # Dependency list (generate with: pip freeze > requirements.txt)
├── static/          # Static files (CSS/JS/images)
│   └── css/
│       └── style.css
└── templates/       # HTML templates
    └── index.html

3. First “Hello World”

Write the basic code in app.py:

from flask import Flask  # Import the Flask class

app = Flask(__name__)    # Create an application instance (__name__ refers to the current module)

@app.route('/')          # Define the route: the function below is executed when accessing the root path
def index():             # View function: handles requests and returns responses
    return "Hello, Flask!"  # Return a string

if __name__ == '__main__':  # Executed when app.py is run directly
    app.run(debug=True)     # Start the development server (debug=True auto-restarts on code changes)

Run the application:

python app.py

Open a browser and visit http://127.0.0.1:5000/ to see “Hello, Flask!”.

4. Routing and Dynamic Parameters

Basic Routing

Besides the root path /, you can define other routes:

@app.route('/about')
def about():
    return "About our project"

@app.route('/user')
def user_profile():
    return "User profile page"

Dynamic Routing Parameters

To get parameters from the URL (e.g., user ID), use the <parameter> syntax:

@app.route('/user/<username>')  # <username> in the URL is passed as a parameter to the function
def show_user(username):
    return f"User: {username}"  # Directly render the parameter

@app.route('/post/<int:post_id>')  # <int:post_id> restricts the parameter to an integer
def show_post(post_id):
    return f"Post ID: {post_id}"

5. Template System (Rendering HTML)

Flask uses the Jinja2 template engine by default. Create HTML files in the templates folder:

templates/index.html:

<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>  <!-- Variable rendering -->
</head>
<body>
    <h1>{{ message }}</h1>
    {% if is_logged_in %}  <!-- Conditional judgment -->
        <p>Welcome back!</p>
    {% else %}
        <p>Please log in first</p>
    {% endif %}
    <ul>
        {% for item in items %}  <!-- Loop through items -->
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
</body>
</html>

Render the template in app.py:

from flask import render_template  # Import the template rendering function

@app.route('/page')
def page():
    data = {
        'title': 'Homepage',
        'message': 'Welcome to Flask templates',
        'is_logged_in': True,
        'items': ['Item 1', 'Item 2', 'Item 3']
    }
    return render_template('index.html', **data)  # Pass data to the template

Static File Reference: Use url_for('static', filename='path') in templates to reference CSS/JS/images:

<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">

6. Handling Forms and Data

Get Form Data

Use the request object to get user input (import first):

from flask import request, render_template, redirect, url_for

@app.route('/login', methods=['GET', 'POST'])  # Allow both GET (display form) and POST (submit data)
def login():
    if request.method == 'POST':  # Check the request method
        username = request.form.get('username')  # Get the 'username' field from the form
        password = request.form.get('password')
        if username == 'admin' and password == '123456':
            return redirect(url_for('dashboard'))  # Redirect to the dashboard page
        else:
            return "Username or password is incorrect"
    return render_template('login.html')  # Display the form for GET requests

Simple Form Validation

Use flask.flash to provide feedback on operation results (e.g., login failure messages):

from flask import flash

@app.route('/login', methods=['POST'])
def login_post():
    if not request.form.get('username'):
        flash('Username cannot be empty', 'error')  # Error message
        return redirect(url_for('login'))
    # ... Other validation logic

Display flash messages in the template:

{% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        {% for category, message in messages %}
            <div class="{{ category }}">{{ message }}</div>
        {% endfor %}
    {% endif %}
{% endwith %}

7. Database Operations (Flask-SQLAlchemy)

Flask does not include built-in database functionality; use extensions. Here’s an example with SQLite (lightweight, no configuration needed):

Install Dependencies

pip install flask-sqlalchemy  # ORM tool to simplify database operations

Initialize the Database

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydb.db'  # SQLite database path
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # Disable modification tracking (saves resources)
db = SQLAlchemy(app)  # Initialize the ORM object

Define Data Models

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)  # Primary key
    username = db.Column(db.String(80), unique=True, nullable=False)  # Username
    email = db.Column(db.String(120), unique=True, nullable=False)  # Email

    def __repr__(self):
        return f'<User {self.username}>'

Create Tables and CRUD Operations

Execute the following commands in the Python interactive environment to create tables:

from app import app, db, User

with app.app_context():  # Application context (avoids runtime errors)
    db.create_all()  # Create all tables based on models

    # Add a user
    user = User(username='test', email='test@example.com')
    db.session.add(user)
    db.session.commit()  # Commit the transaction

    # Query users
    users = User.query.all()  # Query all users
    user = User.query.filter_by(username='test').first()  # Query a single user

    # Delete a user
    db.session.delete(user)
    db.session.commit()

IV. Best Practices for Projects

1. Configuration Management

Avoid hardcoding configurations; separate them using environment variables or config.py:

Method 1: Environment Variables

import os
from dotenv import load_dotenv  # Install with: pip install python-dotenv

load_dotenv()  # Read the .env file
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')  # Get the key from environment variables
app.config['DATABASE_URI'] = os.getenv('DATABASE_URI', 'sqlite:///default.db')  # Default value

.env File (in the root directory):

SECRET_KEY=your_secret_key_here
FLASK_ENV=development

Method 2: Multi-Environment Configuration
Create config.py:

class Config:
    SECRET_KEY = 'your_secret_key'

class DevelopmentConfig(Config):
    DEBUG = True
    DATABASE_URI = 'sqlite:///dev.db'

class ProductionConfig(Config):
    DEBUG = False
    DATABASE_URI = os.getenv('DATABASE_URI')

Load the configuration based on the environment:

app.config.from_object(DevelopmentConfig)  # For development
# app.config.from_object(ProductionConfig)  # For production

2. Code Structure and Blueprints

For larger projects, split functional modules (e.g., user module, order module) using Blueprints:

Create a Blueprint (e.g., users.py)

from flask import Blueprint, render_template

users_bp = Blueprint('users', __name__, url_prefix='/users')  # Route prefix

@users_bp.route('/profile')
def profile():
    return render_template('users/profile.html')

Register the Blueprint (in app.py)

from users import users_bp
app.register_blueprint(users_bp)  # Register the blueprint

After using the blueprint, the access path becomes /users/profile.

3. Error Handling

Customize 404/500 pages to improve user experience:

@app.errorhandler(404)
def not_found(e):
    return render_template('404.html'), 404  # Return status code 404

@app.errorhandler(500)
def server_error(e):
    return render_template('500.html'), 500

4. Logging

Log key operations (e.g., login, errors) for easier debugging:

import logging
from logging.handlers import RotatingFileHandler

def setup_logging(app):
    file_handler = RotatingFileHandler('app.log', maxBytes=10240, backupCount=10)
    file_handler.setFormatter(logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
    ))
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.setLevel(logging.INFO)
    app.logger.info('Flask application started')

# Call after app initialization
setup_logging(app)

5. Testing

Use pytest or Flask’s test client to verify functionality:

# Install pytest: pip install pytest
# test_app.py
import pytest
from app import app, db

@pytest.fixture
def client():
    app.config['TESTING'] = True
    with app.test_client() as client:  # Test client
        with app.app_context():
            db.create_all()
            yield client
            db.drop_all()  # Drop tables after testing

def test_login(client):
    response = client.post('/login', data={'username': 'admin', 'password': '123'}, follow_redirects=True)
    assert response.status_code == 200  # Assert login success (redirect to dashboard)

V. Deployment Introduction

After development, deploy the project to a server for public access:

1. Local Deployment

  • Disable debug in production: app.run(debug=False)
  • Use gunicorn as a WSGI server (more stable than Flask’s built-in server):
  pip install gunicorn
  gunicorn -w 4 -b 0.0.0.0:8000 app:app  # 4 worker processes, bind to port 8000

2. Cloud Platform Deployment

  • PythonAnywhere: Suitable for beginners, upload code + configure virtual environment.
  • Heroku: Requires a Procfile file:
  web: gunicorn app:app

And set environment variables: heroku config:set SECRET_KEY=xxx.

VI. Conclusion

The core of Flask is “lightweight and flexible”. To go from “Hello World” to a complete project, you need to master:
1. Basic routing and view functions
2. Template and static file management
3. Form handling and data validation
4. Database operations (SQLAlchemy)
5. Project structure (blueprints, configuration, logging)

Practice by developing simple projects (e.g., a blog, to-do app) to consolidate knowledge and gradually increase project complexity. Flask has strong extensibility; later, you can integrate extensions like Celery (asynchronous tasks) and Flask-RESTful (API development) to meet more complex needs.

Finally: Coding is the best way to learn. From imitation to independent development, you will gradually master the core logic of web development!

Xiaoye