📊

DjangoチュートリアルをRailsと比較しながらやってみた

に公開

はじめに

こんにちは!最近Djangoチュートリアルに取り組んでみました。今回はDjangoの公式チュートリアルを実際にやってみて、その経験をもとにRailsと比較してみたいと思います。私はフレームワークの中ではRailsによく親しみがあるため、Djangoの特徴や違いがどのように感じられるかを中心にまとめてみました。

アーキテクチャパターンの呼び方の違い

まず最初に、DjangoとRailsではアーキテクチャパターンの呼び方が異なります。

概念 Django (MVT) Rails (MVC)
モデル、DBのテーブルと紐づくレイヤー Model Model
HTMLを返すレイヤー Template View
リクエスト/レスポンスを管理するレイヤー View Controller

DjangoはMVT(Model-View-Template)パターン、RailsはMVC(Model-View-Controller)パターンと呼ばれますが、役割としてはほぼ同じです。
ただし、DjangoのViewはRailsのControllerに相当するという点が最も混乱しやすいポイントですね。

ルーティングの管理方法の違い

DjangoのURLConfとRailsのルーティングは、どちらも「URLをどの処理に結びつけるか」を決める仕組みという点では同じです。しかし、その管理方法には大きな違いがあります。

項目 Rails Django
ファイル名 config/routes.rb urls.py
管理方式 中央集権的(全ルートを1つのファイルで管理) 分散型(アプリごとに分割)
プロジェクト全体のurls.pyが入口となり、各アプリのurls.pyinclude()で取り込む

Rails: 中央集権的なルーティング

# config/routes.rb
Rails.application.routes.draw do
  resources :polls
  resources :comments
  # すべてのルートをここに記述
end

Railsでは、アプリケーション全体のルーティングを1つのファイルで一元管理します。プロジェクトのどこにどんなURLがあるのか、routes.rbを見ればすべて分かるように設計されています。

Django: 分散型のルーティング

一方、Djangoのurls.pyは分散型の設計です。
プロジェクト全体の入り口となるurls.pyがあり、そこから各アプリのurls.pyをinclude()で読み込みます。

# プロジェクト全体の入口のurls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("polls/", include("polls.urls")),  # pollsアプリのURLを取り込む
    path("comments/",  include("comments.urls")),  # commentsアプリのURLを取り込む
    #... 他のアプリも同様
]
# polls/urls.py(pollsアプリ専用のルーティング)
from django.urls import path
from . import views

urlpatterns = [
    path("", views.index, name="index"),  # /polls/ にアクセスするとviews.indexが呼ばれる
    path("<int:question_id>/", views.detail, name="detail"),  # /polls/1/ など
    path("<int:question_id>/results/", views.results, name="results"),
    # ... 他のパスも同様
]

DjangoとRailsのModelの違い

DjangoとRailsのModelは、どちらもORM(Object-Relational Mapping)を提供しますが、いくつかの違いがあります。

項目 Rails Django
テーブルのデータの紐づけ(同じ部分) ORMとしてデータの取得・作成・更新を行う ORMとしてデータの取得・作成・更新を行う
スキーマ定義 db/schema.rbに自動生成 Migrationで管理(Modelから生成)
マイグレーション db/migrate/に個別ファイル Modelから自動生成

管理画面機能の比較

個人的に最も驚いたのがDjango Adminです。本格的なデータ管理画面が、標準機能として提供されています。

項目 Rails Django
標準機能 なし Django Admin(標準搭載)
実現方法 ActiveAdmin、RailsAdminなどのgemが必要 最初から組み込み済み
主な機能 - データベースレコードのCRUD操作
検索・フィルタリング
ユーザー権限管理

Django Adminでできることは以下の通りです。

  • データベースのレコードの閲覧・編集・削除
  • モデルごとのCRUD操作
  • 検索やフィルタリング機能
  • ユーザー権限管理

これがフレームワークに最初から組み込まれているのは、Railsユーザーとしては新鮮でした。

HTTPメソッドの扱いの違い

ここは最も戸惑った部分です。Railsに慣れていると、ルーティングファイルを見ればHTTPメソッドが一目瞭然なのですが、Djangoでは少し事情が異なります。

項目 Rails Django (Function-Based View) Django (Class-Based View)
定義場所 ルーティングファイル(routes.rb ビュー(コントローラー)内 クラスのメソッド名
定義方法 resourcesで一括生成 パスのみ定義し、ビュー側でrequest.methodにより分岐 HTTPメソッドに対応したメソッド名(get, post等)で定義
可視性 ルーティングファイルで全体像を把握可能 ビューのコードを読まないと判断できない クラスのメソッド名である程度推測可能

Railsのアプローチ

resources :posts
# これだけで以下が生成される
# GET    /posts          -> index
# POST   /posts          -> create
# GET    /posts/:id      -> show
# PATCH  /posts/:id      -> update
# DELETE /posts/:id      -> destroy

ルーティングファイルを見れば、どのURLがどのHTTPメソッドに対応しているかが明確です。

Django: Function-Based Viewのアプローチ

# urls.py
urlpatterns = [
    path('posts/', views.post_list),
    path('posts/<int:pk>/', views.post_detail),
]

# views.py
def post_detail(request, pk):
    if request.method == 'GET':
        # 取得処理
    elif request.method == 'POST':
        # 作成処理
    elif request.method == 'DELETE':
        # 削除処理

この設計は、同じURLに対して複数のHTTPメソッドを柔軟に処理できる反面、ルーティングファイルだけではAPIの全体像が把握しにくいと感じました。

Django: Class-Based Viewのアプローチ

Djangoチュートリアルでは扱われていませんが、DjangoにはClass-Based View(CBV)という選択肢もあります。これはRailsのコントローラーに近い感覚で使えそうです。

# urls.py
from django.urls import path
from .views import PostListView, PostDetailView

urlpatterns = [
    path('posts/', PostListView.as_view()),
    path('posts/<int:pk>/', PostDetailView.as_view()),
]

# views.py
from django.views import View
from django.views.generic import ListView, DetailView

# 汎用ビューを使う場合(よりシンプル)
class PostListView(ListView):
    model = Post
    template_name = 'posts/list.html'
    context_object_name = 'posts'

class PostDetailView(DetailView):
    model = Post
    template_name = 'posts/detail.html'
    context_object_name = 'post'

# または、基本のViewクラスを使う場合
class PostDetailView(View):
    def get(self, request, pk):
        # GET処理
        post = Post.objects.get(pk=pk)
        return render(request, 'posts/detail.html', {'post': post})
    
    def post(self, request, pk):
        # POST処理
        pass
    
    def delete(self, request, pk):
        # DELETE処理
        pass

Class-Based Viewを使うと、以下のメリットがあります。

  • HTTPメソッドごとにメソッドを分離できる(get(), post(), put(), delete()等)
  • コードの見通しが良くなる

個人的には、Function-Based Viewよりも、このClass-Based Viewの方がRailsユーザーには馴染みやすいと感じました。

まとめ

比較項目 Rails Django
アーキテクチャ MVC MVT(ViewとTemplateの呼び方が逆)
ルーティング 中央集権的(1ファイルで管理) 分散型(アプリごとに分割)
モデル設計 スキーマとマイグレーションが分離 Modelクラスが全てを統合
管理画面 gemの追加が必要 標準搭載(Django Admin)
HTTPメソッド ルーティングで明示 FBV: ビュー内で分岐処理
CBV: メソッド名で分離

おわりに

正直なところ、最初は「Pythonで書くRails」程度の認識でDjangoに触れましたが、実際に使ってみるとまったく異なる設計思想を持つフレームワークでした。

  1. Django Admin の完成度の高さ: これが標準というのは驚きでした
  2. 分散型のルーティング: アプリごとにurls.pyを持つ設計は、Railsの中央集権的な管理とは対照的なアプローチでした
  3. HTTPメソッドの扱い方: ルーティングではなくビュー側で分岐する設計は、Railsとは真逆のアプローチでした

実際のプロジェクトでDjangoを使って、さらに理解を深めていきたいと思います!

Discussion