🍣

DjangoとRailsの記法について比較してみた #2

2022/06/05に公開約8,600字

はじめに

本記事の目的

初めてwebアプリフレームワークを学ぶにあたってMTVモデルであるDjango(Python)を選んだ筆者が、Djangoと適宜比較しながらMVCモデルであるRuby on Railsをキャッチアップする

本記事を読み進めるにあたっての前提

本記事は第2弾になります
記事を書くに至った背景等は前回記事参照。
Django使いがキャッチアップのためにRails(+Docker)を触ってみた(#1 環境構築編 2022年)

  • 今回はDjangoとRailsのMTV(MVC)周りを中心に進めていきます。
  • DjangoとRailsの記法等を比較していきながら、Railsの特徴とそれに対する印象を述べていきます。

※以下の内容は、

  • あくまで学習初期の現時点での印象を記載していきます。
    (そのため、見当違いな考えを述べている可能性がある点ご留意願います。
    私自身まだ使用している月日が長くないため考察しきれていないのですが、実はこういった設計になっているのは、この点でメリットがある・こうゆう理由が考え得るなどのコメント等ございましたら、お待ちしております。)

  • 学習を進めていき次第、適宜付け足し・修正していきます

1. アプリ作成~基本的なコマンド

項目 Django Rails
プロジェクトの作成 django-admin startproject project -
アプリの作成 python manage.py startapp app rails new rails-app
開発サーバ起動 python manage.py runserver rails server
rails s
コンソール起動 python manage.py shell rails console
rails c
  • 上記に限らずDjangoではpython manage.pyを起点にして作業をする一方、
    Railsではrailsコマンドをもとに作業を進めていくようです

初期ディレクトリ・ファイル構成

Django
project/
    manage.py
    project/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py
    app/
        __init__.py
        admin.py
        apps.py
        migrations
        models.py
        tests.py
        urls.py
        views.py
Rails(※抜粋して記載)
.
└── rails-app
    ├── app
    │   ├── assets
    │   ├── channels
    │   ├── controllers
    │   ├── helpers
    │   ├── javascript
    │   ├── jobs
    │   ├── mailers
    │   ├── models
    │   └── views
    ├── bin
    ├── config
    │   ├── environments
    │   ├── initializers
    │   ├── locales
    │   └── webpack
    │   ├── application.rb
    │   ├── boot.rb
    │   ├── cable.yml
    │   ├── credentials.yml.enc
    │   ├── database.yml
    │   ├── environment.rb
    │   ├── environments
    │   ├── initializers
    │   ├── locales
    │   ├── master.key
    │   ├── puma.rb
    │   ├── routes.rb
    │   ├── spring.rb
    │   ├── storage.yml
    │   ├── webpack
    │   └── webpacker.yml
    ├── db
    │   └── migrate
    ├── lib
    │   ├── assets
    │   └── tasks
    ├── log
    ├── node_modules
    ├── public
    │   └── packs
    ├── storage
    ├── test
    │   ├── channels
    │   ├── controllers
    │   ├── fixtures
    │   ├── helpers
    │   ├── integration
    │   ├── mailers
    │   ├── models
    │   └── system
    ├── tmp
    │   ├── cache
    │   ├── pids
    │   ├── sockets
    │   └── storage
    └── vendor
  • 上記からわかるようにDjangoに比べて、Railsではアプリ作成の段階で多くのファイルが生成されます。

    • Djangoに慣れている身からすると、ファイルが大量に生成されてどこになにがあるのか把握するのが少し大変でした。ただ、使い慣れていけば逆に最初の段階で一連のファイルを生成してくれるのはありがたいと(おそらく)感じるようになるはず

2.Model

Django
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=50)

    def display(self):
        return f'No{self.id}:{self.name}'
Ruby
class User < ApplicationRecord
  def display
    return "No#{self.id}:#{self.name}"
  end
end

以下適宜、RailsとDjangoで感じた相違点を表にまとめていきます

項目 Rails Django
1.クラス・モジュールの読み込み app/ディレクトリ下のものはrequire明示なし 毎回import明示
2.カラム情報記載場所 db/schema.rb model.py
3.マイグレーション rails generate modelコマンドが起点
(rails generate modelコマンド時にカラム情報も打ち込むことでファイル作成)
model.pyが起点
(model.pyにカラム設計を書き込んでから、python manage.py makemigrationsコマンドでファイル作成
  1. Djangoではファイル内で使用するクラス・モジュールは基本、明示的にimportをします
    Railsには「オートロード(autoloading: 自動読み込み)」により、よく使用する基本クラス等は明示的にrequireしなくてもいいようです



  2. DjangoではDBテーブルのカラムに対応したフィールドやメソッドを基本model.pyに書き込みます
    Railsではカラム情報はrails generate modelコマンドを実施した際にdb/schema.rbに記載され、加えてバリデーションやメソッドを追加する際に、app/models/xxx(モデル名).rbに追加で書き込む流れのようです

    • Djangoではカラム情報等を確認する際モデルから見ることが多いためこの辺は少し慣れが必要そうと感じました

  3. Djangoではmodel.pyが起点のため、マイグレーションの際は、model.pyに書込後→python manage.py makemigrations&python manage.py migrateという流れで操作します
    Railsではrails generate modelでまずファイルを作成して、必要ならば追加で情報書込み後rails db:migrateという流れのようです

    • Railsを触ってみて、まずここにDjangoとの違いを感じました
      Railsではrailsコマンドで基本的なカラム定義とファイル作成を自動で行ってくれるところに利便性を感じました

3.Controller(View)

※以下RailsについてはContoller、DjangoについてはViewと表記します

Djangoパターン1(関数の場合)
from app.models import User
from django.shortcuts import render

def index(request):
    return render(request, 'users/index.html', {'users':User.objects.all()})

def detail(request,id):
    return render(request, 'users/detail.html', {'user':User.objects.get(id=id)})

Djangoパターン2(汎用クラスの場合)
from django.views import generic
from app.models import User

class IndexView(generic.ListView):
    model = User
    template_name = 'users/index.html'

class DetailView(generic.DetailView):
    model = User
    template_name = 'users/detail.html'
Rails
class UserContoller < ApplicationController
    def index
        @users = User.all
    end

    def show
        @user = User.find(params[:id])
    end
end
項目 Rails Django
1.ORM Model.all
Model.find(id=1)
Model.objects.all()
Model.objects.get(id=1)
2.View(Templete)への変数受け渡し @arg arg
3.View(Templete)のファイル作成 Railsコマンドで自動作成 別途自分で作成
4.メソッドの引数 引数の明示なし ①request及びURLディスパッチャから来る引数を明示
②引数の明示なし
  1. Djangoではobjectsというマネージャークラスを通してデータベースクエリ操作が行わるため、記法はModel.objects.method()という形になります。
    RailsではModel.method()という形のようです。

    • objectsを記載しなくていい分、記載量が減るのでシンプルに書けそうです。
      Djangoでまれにマネージャークラスでカスタムすることがあるので、どちらの設計のほうが扱いやすいかは要検証

  2. 特になし

  3. DjangoではTempleteの作成は別途個別で行う必要があります
    RailsではRails generate controllerでコントローラ生成の際に、app/views以下に自動作成してくれます

    • Railsではapp/views以下にコントローラ名でフォルダ分けしながら自動作成してくれることで、ビューの作成場所・ファイル名に悩むことなく一貫したファイル管理ができる工夫があると思いました。
      Djangoの汎用クラスビューではデフォルトでは<app name>/<model name>_xxx.htmlといったファイル名が設定されていますが、テンプレートファイルはテンプレートフォルダ以下にまとめることが多いと思われるため、デフォルトで使用することは少なく、テンプレート保管場所・ファイル名の決定がこちらにあるのは、慣れてないうちは管理が煩雑になりやすい・ファイル作成の手間がかかるかなあという印象です。

  4. Djangoではテンプレートへのレンダリングをする記法は関数またはクラスのどちらかで書くことができます。関数で書く場合には、第1引数にrequestオブジェクト・それ以降にURLパラメータから来る引数を明示する必要があります(ただ実際にはDjangoのフレームワークを活用する場合は汎用クラスで書くのが基本になると思います)
    Railsでは基本クラスで記述し引数の明示はなく、URLパラメータから来る引数は[:xx]の形で受け取ります

    • (おそらく)Ruby/Pythonの言語仕様からくるものかと思いますがRubyのほうが記述量は少ないですね

4.View(Templete)

※以下RailsについてはView、DjangoについてはTempleteと表記します

Django
<html>
  <ul>
  {% for user in users %}
    <li>
      <a href="{% url 'detail' user.id %}">{{ user.name }}</a>
    </li>
  {% endfor %}
  </ul>
</html>
Rails
<ul>
  <% @users.each do |user| %>
    <li>
      <%= link_to user.name, user %>
    </li>
  <% end %>
</ul>
項目 Rails Django
1.記法 <% %>及び<%= %> {% %}
2.Controller(View)からの変数受取 <% @arg %> {% arg %}
3.Controller(View)へのリンク記法 URLヘルパーによるモデルオブジェクトからパスへの変換 URLconfによる名前空間
  1. 特にコメントなし

  2. 特にコメントなし

  3. DjangoではURLに対応した名前空間をルーティングにて設定(ルーティング部分のname='detail'の箇所)し、テンプレートにてaタグ内のhref属性に{% url 'detail' %}及び渡したいパラメータuser.idを渡すことでリンクを設定します
    Railsはlink_toヘルパーにモデルオブジェクトuserを渡すことでリンクを設定します

    • これはRailsの方がとてもシンプルだと感じました

5.ルーティング

Djangoパターン1(関数の場合)
from django.urls import path
from views import user

urlpatterns = [
    path('user', user.index, name='index'),
    path('user/<int:id>', user.detail, name='detail'),
]
Djangoパターン2(汎用クラスの場合)
from django.urls import path
from views import UserListView, UserDetailView

urlpatterns = [
    path('user', UserListView.as_view(), name='list'),
    path('user/<int:id>', UserDetailView.as_view(), name='detail'),
]

Rails
Rails.applications.routes.draw do
  get 'user' => 'user#index'
  get 'user/:id' => 'user#detail'
end

項目 Rails Django
1.パラメータ変数 :arg <int:arg>
2.Controler(View)への設定 controler#method view.method
3.HTTPメソッドでのルーティング ルーティング部分で分岐できる ルーティング先のViewで分岐させる
  1. Djangoでは<int : arg>で構成されます。arg>で変数名を既定し、<intの部分はパスコンバータと呼ばれ、URLパスのこの部分に一致するパターンを決定するコンバーターのようです(URLディスパッチャー周りについてはまだ未調査・・)
    Railsでは:argと書きます

  2. 特にコメントなし

  3. Djangoではルーティング部分はURLとViewを対応付けするだけであり、HTTPメソッドによる場合分けはView部分で実装します
    Railsではルーティングの時点でHTTPメソッドに応じてController先を分岐できます

    • どちらの設計のほうが扱いやすいかは要検証

終わりに

ざっくりですがまずはRailsのMVC周りを確認してみました。
第一印象としては、

  • ファイル作成等の際はRailsコマンドが起点として、コマンドに応じて基本的な情報を書き込んでファイルが自動的に作成してくれるあたりが充実している
  • Rubyとの記法も合わさって、汎用的な操作についての書き下すコード分量が少なくすむ

といった点で良い印象を受けました。

そして、最初の目的であるDjango使いがRailsをキャッチアップしやすいか否かの点ですが、
基本的なMVC周りに関しては、慣れは必要ですが特に違和感なく把握できたという感触です。

今後の予定

今後の予定としてはRailsにある程度慣れていった際に、再度DjangoとRailsの比較をしつつ、DjangoとRailsおよびPythonとRubyの特徴・良し悪しなどを考察しながら、フレームワーク・言語仕様についての理解を深めていければと考えています。

次回としては以下のいずれかに触れていければと考えています。

  • DjangoとRailsの細かい違い(ORM周りの記法など)
  • Django REST FrameworkとRails APIモードの違い
  • PythonとRubyの記法の違い

Discussion

ログインするとコメントできます