TechHub

エンジニアの成長をサポートする技術情報サイト

← 記事一覧に戻る

PythonでWebアプリケーションを構築する方法:FlaskとDjango

公開日: 2024年2月12日 著者: mogura
PythonでWebアプリケーションを構築する方法:FlaskとDjango

疑問

PythonでWebアプリケーションを構築するには、どのようなフレームワークを使用すればよいのでしょうか?FlaskとDjangoの使い方について一緒に学んでいきましょう。

導入

Pythonは、Webアプリケーション開発において人気の高い言語です。FlaskとDjangoは、PythonでWebアプリケーションを構築するための主要なフレームワークです。

Flaskは軽量で柔軟性が高く、小規模から中規模のアプリケーションに適しています。一方、Djangoは包括的な機能を備えており、中規模から大規模のアプリケーションに適しています。

本記事では、FlaskとDjangoの基本から、実践的なWebアプリケーションの構築方法まで、詳しく解説していきます。初心者の方でも理解できるよう、具体的なコード例を豊富に用意しました。

Python Webアプリケーションのイメージ

解説

1. FlaskとDjangoの違い

FlaskとDjangoは、それぞれ異なる設計思想と特徴を持っています。Flaskは「マイクロフレームワーク」として設計されており、最小限の機能から始められます。一方、Djangoは「包括的なフレームワーク」として設計されており、多くの機能が組み込まれています。プロジェクトの要件に応じて適切なフレームワークを選択することが重要です。

Flask

Flaskの主な特徴:

- 軽量: 最小限の機能から始められるマイクロフレームワーク
- 柔軟性: 必要な機能を拡張機能として追加できる
- 学習曲線: 比較的緩やかで、初心者にも理解しやすい
- 用途: 小規模から中規模のアプリケーション、RESTful API、プロトタイプ開発
- 拡張性: Flask-Extensionエコシステムが豊富
- 制約の少なさ: プロジェクト構造を自由に設計できる

Flaskが適している場合
- シンプルなWebアプリケーション
- RESTful APIの開発
- プロトタイプの迅速な開発
- カスタマイズ性を重視する場合

Django

Djangoの主な特徴:

- 包括的: 多くの機能が組み込まれている(ORM、認証、管理画面など)
- 規約: 規約に従った開発(Convention over Configuration)
- 学習曲線: やや急だが、一度習得すれば効率的に開発できる
- 用途: 中規模から大規模のアプリケーション、コンテンツ管理システム、SNS
- セキュリティ: デフォルトで多くのセキュリティ機能が有効
- 管理画面: 自動生成される管理画面(Django Admin)

Djangoが適している場合
- 大規模なWebアプリケーション
- データベース中心のアプリケーション
- 管理画面が必要な場合
- チーム開発で規約に従った開発を重視する場合

2. Flaskの基本

Flaskは、最小限のコードでWebアプリケーションを構築できる軽量なフレームワークです。基本的な使い方から、ルーティング、テンプレート、データベース統合まで学びましょう。Flaskは柔軟性が高く、必要な機能を段階的に追加できます。

インストールとセットアップ

Flaskをインストールする方法:

# pipでインストール
pip install flask

# 仮想環境を使用する場合(推奨)
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install flask


プロジェクト構造の例
myapp/
  app.py
  templates/
    index.html
  static/
    css/
    js/

最小限のFlaskアプリケーション

最小限のFlaskアプリケーションの例:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run(debug=True)


実行方法
python app.py


ブラウザでhttp://localhost:5000にアクセスすると、「Hello, World!」が表示されます。

ルーティング

Flaskでは、@app.route()デコレータを使用してルートを定義します。

基本的なルーティング

@app.route('/')
def index():
    return 'ホームページ'

@app.route('/about')
def about():
    return 'Aboutページ'


動的なルーティング
@app.route('/user/<username>')
def show_user(username):
    return f'ユーザー: {username}'

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'投稿ID: {post_id}'


HTTPメソッドの指定
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # POSTリクエストの処理
        return 'ログイン処理'
    # GETリクエストの処理
    return 'ログインフォーム'

テンプレートの使用

Flaskでは、Jinja2テンプレートエンジンを使用してHTMLテンプレートをレンダリングできます。

テンプレートファイル(templates/index.html)

<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
</body>
</html>


Flaskアプリケーション
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', 
                          title='ホーム', 
                          message='ようこそ!')


テンプレート継承
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>

<!-- templates/index.html -->
{% extends 'base.html' %}
{% block title %}ホーム{% endblock %}
{% block content %}
    <h1>ホームページ</h1>
{% endblock %}

データベース統合(SQLAlchemy)

Flaskでは、SQLAlchemyを使用してデータベースを統合できます。

インストール

pip install flask-sqlalchemy


基本的な使用例
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

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

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    
    def __repr__(self):
        return f'<User {self.username}>'

# データベースの作成
with app.app_context():
    db.create_all()

# ユーザーの作成
@app.route('/user/<username>')
def create_user(username):
    user = User(username=username, email=f'{username}@example.com')
    db.session.add(user)
    db.session.commit()
    return f'ユーザー {username} を作成しました'

基本的なFlaskアプリケーション

ルーティング、テンプレート、フォーム処理を含む基本的なFlaskアプリケーションの例です。

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///tasks.db'
db = SQLAlchemy(app)

class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    completed = db.Column(db.Boolean, default=False)
    
    def __repr__(self):
        return f'<Task {self.title}>'

@app.route('/')
def index():
    tasks = Task.query.all()
    return render_template('index.html', tasks=tasks)

@app.route('/add', methods=['POST'])
def add_task():
    title = request.form.get('title')
    if title:
        task = Task(title=title)
        db.session.add(task)
        db.session.commit()
        flash('タスクを追加しました')
    return redirect(url_for('index'))

@app.route('/complete/<int:task_id>')
def complete_task(task_id):
    task = Task.query.get_or_404(task_id)
    task.completed = True
    db.session.commit()
    flash('タスクを完了しました')
    return redirect(url_for('index'))

@app.route('/delete/<int:task_id>')
def delete_task(task_id):
    task = Task.query.get_or_404(task_id)
    db.session.delete(task)
    db.session.commit()
    flash('タスクを削除しました')
    return redirect(url_for('index'))

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

RESTful APIの例

Flaskを使用したRESTful APIの例です。

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy

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

class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    price = db.Column(db.Float, nullable=False)
    
    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'price': self.price
        }

@app.route('/api/products', methods=['GET'])
def get_products():
    products = Product.query.all()
    return jsonify([p.to_dict() for p in products])

@app.route('/api/products/<int:product_id>', methods=['GET'])
def get_product(product_id):
    product = Product.query.get_or_404(product_id)
    return jsonify(product.to_dict())

@app.route('/api/products', methods=['POST'])
def create_product():
    data = request.get_json()
    product = Product(name=data['name'], price=data['price'])
    db.session.add(product)
    db.session.commit()
    return jsonify(product.to_dict()), 201

@app.route('/api/products/<int:product_id>', methods=['PUT'])
def update_product(product_id):
    product = Product.query.get_or_404(product_id)
    data = request.get_json()
    product.name = data.get('name', product.name)
    product.price = data.get('price', product.price)
    db.session.commit()
    return jsonify(product.to_dict())

@app.route('/api/products/<int:product_id>', methods=['DELETE'])
def delete_product(product_id):
    product = Product.query.get_or_404(product_id)
    db.session.delete(product)
    db.session.commit()
    return '', 204

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

3. Djangoの基本

Djangoは、包括的な機能を備えたWebフレームワークです。プロジェクト構造、ビュー、URL設定、モデル、マイグレーションなど、Djangoの基本概念を学びましょう。Djangoは規約に従った開発を重視し、多くの機能がデフォルトで組み込まれています。

インストールとセットアップ

Djangoをインストールする方法:

# pipでインストール
pip install django

# 仮想環境を使用する場合(推奨)
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install django


プロジェクトの作成
# プロジェクトを作成
django-admin startproject myproject
cd myproject

# アプリケーションを作成
python manage.py startapp myapp

プロジェクト構造

Djangoプロジェクトの構造:

myproject/
  manage.py
  myproject/
    __init__.py
    settings.py
    urls.py
    wsgi.py
    asgi.py
  myapp/
    __init__.py
    admin.py
    apps.py
    models.py
    views.py
    tests.py
    migrations/


主要なファイル
- manage.py: プロジェクト管理スクリプト
- settings.py: プロジェクト設定
- urls.py: URL設定
- models.py: データモデル定義
- views.py: ビュー関数
- admin.py: 管理画面設定

基本的なビュー

Djangoでは、ビュー関数またはクラスベースビューを使用してリクエストを処理します。

関数ベースビュー

# myapp/views.py
from django.http import HttpResponse
from django.shortcuts import render

def index(request):
    return HttpResponse('Hello, World!')

def about(request):
    context = {'title': 'About', 'message': 'Aboutページです'}
    return render(request, 'myapp/about.html', context)


クラスベースビュー
from django.views.generic import ListView, DetailView
from .models import Post

class PostListView(ListView):
    model = Post
    template_name = 'myapp/post_list.html'
    context_object_name = 'posts'

class PostDetailView(DetailView):
    model = Post
    template_name = 'myapp/post_detail.html'

URL設定

Djangoでは、URLパターンをurls.pyで定義します。

プロジェクトのURL設定(myproject/urls.py)

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls')),
]


アプリケーションのURL設定(myapp/urls.py)
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('about/', views.about, name='about'),
    path('post/<int:post_id>/', views.post_detail, name='post_detail'),
]


名前付きURLの使用
# テンプレート内
<a href="{% url 'post_detail' post_id=1 %}">投稿を表示</a>

# ビュー内
from django.shortcuts import redirect
return redirect('post_detail', post_id=1)

モデル定義

Djangoでは、models.pyでデータモデルを定義します。

基本的なモデル

# myapp/models.py
from django.db import models
from django.utils import timezone

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.CharField(max_length=100)
    published_date = models.DateTimeField(default=timezone.now)
    created_date = models.DateTimeField(auto_now_add=True)
    updated_date = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.title
    
    class Meta:
        ordering = ['-published_date']

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    author = models.CharField(max_length=100)
    text = models.TextField()
    created_date = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return f'{self.author} - {self.post.title}'

マイグレーション

Djangoでは、マイグレーションを使用してデータベーススキーマを管理します。

マイグレーションの作成と適用

# マイグレーションファイルを作成
python manage.py makemigrations

# マイグレーションを適用
python manage.py migrate

# マイグレーションの状態を確認
python manage.py showmigrations


マイグレーションのロールバック
# 特定のマイグレーションまでロールバック
python manage.py migrate myapp 0001

# すべてのマイグレーションをロールバック
python manage.py migrate myapp zero

Django REST Framework

Django REST Framework(DRF)は、DjangoでRESTful APIを構築するための強力なツールです。

インストール

pip install djangorestframework


基本的な使用例
# myapp/serializers.py
from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'content', 'author', 'published_date']

# myapp/views.py
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

# myapp/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import PostViewSet

router = DefaultRouter()
router.register(r'posts', PostViewSet)

urlpatterns = [
    path('api/', include(router.urls)),
]

基本的なDjangoアプリケーション

モデル、ビュー、テンプレートを含む基本的なDjangoアプリケーションの例です。

# myapp/models.py
from django.db import models
from django.utils import timezone

class BlogPost(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.CharField(max_length=100)
    published_date = models.DateTimeField(default=timezone.now)
    
    def __str__(self):
        return self.title
    
    class Meta:
        ordering = ['-published_date']

# myapp/views.py
from django.shortcuts import render, get_object_or_404
from .models import BlogPost

def post_list(request):
    posts = BlogPost.objects.all()
    return render(request, 'myapp/post_list.html', {'posts': posts})

def post_detail(request, post_id):
    post = get_object_or_404(BlogPost, id=post_id)
    return render(request, 'myapp/post_detail.html', {'post': post})

# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post/<int:post_id>/', views.post_detail, name='post_detail'),
]

# myapp/admin.py
from django.contrib import admin
from .models import BlogPost

@admin.register(BlogPost)
class BlogPostAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'published_date']
    list_filter = ['published_date']
    search_fields = ['title', 'content']

Django REST Frameworkの例

Django REST Frameworkを使用したRESTful APIの例です。

# myapp/serializers.py
from rest_framework import serializers
from .models import BlogPost

class BlogPostSerializer(serializers.ModelSerializer):
    class Meta:
        model = BlogPost
        fields = ['id', 'title', 'content', 'author', 'published_date']
        read_only_fields = ['published_date']

# myapp/views.py
from rest_framework import viewsets, permissions
from .models import BlogPost
from .serializers import BlogPostSerializer

class BlogPostViewSet(viewsets.ModelViewSet):
    queryset = BlogPost.objects.all()
    serializer_class = BlogPostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    
    def perform_create(self, serializer):
        serializer.save(author=self.request.user.username)

# myapp/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BlogPostViewSet

router = DefaultRouter()
router.register(r'posts', BlogPostViewSet)

urlpatterns = [
    path('api/', include(router.urls)),
]

4. 実践的なプロジェクト例

FlaskとDjangoを使用した実践的なプロジェクト例を紹介します。RESTful APIやブログアプリケーションなど、実際の開発で役立つ例を学びましょう。これらの例を通じて、フレームワークの使い方を理解できます。

Flask: RESTful API

Flaskを使用したRESTful APIの実装例:

機能
- 商品の一覧取得(GET /api/products)
- 商品の詳細取得(GET /api/products/<id>)
- 商品の作成(POST /api/products)
- 商品の更新(PUT /api/products/<id>)
- 商品の削除(DELETE /api/products/<id>)

特徴
- JSON形式でのデータのやり取り
- エラーハンドリング
- バリデーション
- SQLAlchemyを使用したデータベース操作

Django: ブログアプリケーション

Djangoを使用したブログアプリケーションの実装例:

機能
- ブログ投稿の一覧表示
- ブログ投稿の詳細表示
- ブログ投稿の作成・編集・削除(管理画面)
- コメント機能
- カテゴリ機能
- タグ機能

特徴
- Django Adminを使用した管理画面
- テンプレート継承
- フォーム処理
- ページネーション
- 検索機能

Flask: ToDoアプリケーション

Flaskを使用したToDoアプリケーションの完全な実装例です。

from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    description = db.Column(db.Text)
    completed = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    def to_dict(self):
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'completed': self.completed,
            'created_at': self.created_at.isoformat()
        }

@app.route('/')
def index():
    tasks = Task.query.order_by(Task.created_at.desc()).all()
    return render_template('index.html', tasks=tasks)

@app.route('/api/tasks', methods=['GET'])
def get_tasks():
    tasks = Task.query.all()
    return jsonify([task.to_dict() for task in tasks])

@app.route('/api/tasks', methods=['POST'])
def create_task():
    data = request.get_json()
    task = Task(
        title=data.get('title'),
        description=data.get('description', '')
    )
    db.session.add(task)
    db.session.commit()
    return jsonify(task.to_dict()), 201

@app.route('/api/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
    task = Task.query.get_or_404(task_id)
    data = request.get_json()
    task.title = data.get('title', task.title)
    task.description = data.get('description', task.description)
    task.completed = data.get('completed', task.completed)
    db.session.commit()
    return jsonify(task.to_dict())

@app.route('/api/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = Task.query.get_or_404(task_id)
    db.session.delete(task)
    db.session.commit()
    return '', 204

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

Django: ブログアプリケーション

Djangoを使用したブログアプリケーションの完全な実装例です。

# models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField(max_length=100)
    
    def __str__(self):
        return self.name

class Tag(models.Model):
    name = models.CharField(max_length=50)
    
    def __str__(self):
        return self.name

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    tags = models.ManyToManyField(Tag, blank=True)
    published_date = models.DateTimeField(default=timezone.now)
    created_date = models.DateTimeField(auto_now_add=True)
    updated_date = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.title
    
    class Meta:
        ordering = ['-published_date']

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.CharField(max_length=100)
    text = models.TextField()
    created_date = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return f'{self.author} - {self.post.title}'

# views.py
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator
from .models import Post, Category

def post_list(request):
    posts = Post.objects.all()
    paginator = Paginator(posts, 5)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'blog/post_list.html', {'page_obj': page_obj})

def post_detail(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    return render(request, 'blog/post_detail.html', {'post': post})

# admin.py
from django.contrib import admin
from .models import Post, Category, Tag, Comment

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'category', 'published_date']
    list_filter = ['published_date', 'category']
    search_fields = ['title', 'content']
    filter_horizontal = ['tags']

admin.site.register(Category)
admin.site.register(Tag)
admin.site.register(Comment)

5. ベストプラクティス

FlaskとDjangoを使用する際のベストプラクティスをまとめます。セキュリティ、パフォーマンス、コードの構造化など、実践的なアドバイスを提供します。

FlaskとDjangoを使用する際のベストプラクティスをまとめます。セキュリティ、パフォーマンス、コードの構造化など、実践的なアドバイスを提供します。これらのベストプラクティスを守ることで、堅牢で保守しやすいWebアプリケーションを構築できます。

Flask

Flaskのベストプラクティス:

- アプリケーションファクトリーパターン: アプリケーションインスタンスを関数で作成
- 設定の管理: 環境変数や設定ファイルを使用
- ブループリントの使用: 大規模なアプリケーションをモジュール化
- エラーハンドリング: 適切なエラーハンドリングを実装
- セキュリティ: CSRF保護、XSS対策、SQLインジェクション対策
- ロギング: 適切なロギングを実装
- テスト: ユニットテストと統合テストを書く

アプリケーションファクトリーの例

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app(config_name='development'):
    app = Flask(__name__)
    app.config.from_object(f'config.{config_name}')
    db.init_app(app)
    
    from .routes import main
    app.register_blueprint(main)
    
    return app

Django

Djangoのベストプラクティス:

- 設定の分離: 開発環境と本番環境で設定を分離
- 環境変数の使用: 機密情報は環境変数で管理
- アプリケーションの分割: 機能ごとにアプリケーションを分割
- クラスベースビューの使用: 再利用性の高いビューを作成
- ミドルウェアの活用: 認証、ロギング、セキュリティなど
- キャッシュの使用: パフォーマンス向上のため
- テスト: テスト駆動開発を実践
- セキュリティ: Djangoのセキュリティ機能を活用

設定の分離例

# settings/base.py
# 共通設定

# settings/development.py
from .base import *
DEBUG = True
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# settings/production.py
from .base import *
DEBUG = False
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST'),
        'PORT': os.environ.get('DB_PORT'),
    }
}

Flask: アプリケーションファクトリーとブループリント

Flaskのアプリケーションファクトリーパターンとブループリントを使用した例です。

# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config

db = SQLAlchemy()

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    db.init_app(app)
    
    from app.routes import main
    app.register_blueprint(main)
    
    from app.api import api
    app.register_blueprint(api, url_prefix='/api')
    
    return app

# app/routes.py
from flask import Blueprint, render_template

main = Blueprint('main', __name__)

@main.route('/')
def index():
    return render_template('index.html')

# app/api/__init__.py
from flask import Blueprint

api = Blueprint('api', __name__)

from app.api import routes

# app/api/routes.py
from app.api import api
from flask import jsonify

@api.route('/status')
def status():
    return jsonify({'status': 'ok'})

# run.py
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(debug=True)

Django: 設定の分離と環境変数

Djangoの設定を分離し、環境変数を使用する例です。

# settings/base.py
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-key')

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'myproject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'myproject.wsgi.application'

# settings/development.py
from .base import *

DEBUG = True

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# settings/production.py
from .base import *

DEBUG = False

ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

6. どちらを選ぶべきか

FlaskとDjangoのどちらを選ぶべきかは、プロジェクトの要件によって異なります。それぞれの特徴を理解し、適切なフレームワークを選択しましょう。プロジェクトの規模、チームの経験、必要な機能などを考慮して決定します。

Flaskが適している場合

Flaskが適している場合:

- 小規模から中規模のアプリケーション: シンプルなWebアプリケーションやAPI
- 柔軟性を重視: プロジェクト構造を自由に設計したい場合
- 学習コストを抑えたい: 初心者でも比較的簡単に始められる
- RESTful APIの開発: API専用のアプリケーション
- プロトタイプの迅速な開発: 迅速にプロトタイプを作成したい場合
- マイクロサービス: 小さな独立したサービスを構築する場合
- カスタマイズ性: フレームワークの制約を最小限にしたい場合

具体例
- シンプルなブログ
- RESTful API
- プロトタイプ
- マイクロサービス
- データ可視化ダッシュボード

Djangoが適している場合

Djangoが適している場合:

- 中規模から大規模のアプリケーション: 複雑な機能を持つWebアプリケーション
- データベース中心のアプリケーション: 多くのデータモデルとリレーションが必要な場合
- 管理画面が必要: Django Adminを使用して管理画面を簡単に作成したい場合
- セキュリティを重視: デフォルトで多くのセキュリティ機能が有効
- チーム開発: 規約に従った開発でチーム全体の生産性を向上させたい場合
- 認証・認可機能: ユーザー認証や権限管理が必要な場合
- コンテンツ管理システム: CMSのようなアプリケーション

具体例
- SNSアプリケーション
- ECサイト
- コンテンツ管理システム
- 企業向けアプリケーション
- 複雑なデータベース操作が必要なアプリケーション

まとめ

PythonでWebアプリケーションを構築するには、FlaskとDjangoという2つの主要なフレームワークがあります。Flaskは軽量で柔軟性が高く、小規模から中規模のアプリケーションやRESTful APIの開発に適しています。一方、Djangoは包括的な機能を備えており、中規模から大規模のアプリケーションやデータベース中心のアプリケーションに適しています。

プロジェクトの規模と要件に応じて適切なフレームワークを選択し、実践的なプロジェクトを作成することで、効率的にWebアプリケーション開発のスキルを向上させることができます。

実践的なプロジェクトでFlaskやDjangoを使用し、経験を積むことで、より効率的で保守しやすいWebアプリケーションを構築できるようになります。セキュリティやパフォーマンスにも注意を払い、ベストプラクティスに従って開発することが重要です。

Pythonでファイルを読み書きする方法は?実践的なガイド