DjangoとRailsの記法について比較してみた #2
はじめに
本記事の目的
初めて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コマンドをもとに作業を進めていくようです
初期ディレクトリ・ファイル構成
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-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
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}'
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 コマンドでファイル作成 |
-
Djangoではファイル内で使用するクラス・モジュールは基本、明示的にimportをします
Railsには「オートロード(autoloading: 自動読み込み)」により、よく使用する基本クラス等は明示的にrequireしなくてもいいようです
-
DjangoではDBテーブルのカラムに対応したフィールドやメソッドを基本
model.py
に書き込みます
Railsではカラム情報はrails generate model
コマンドを実施した際にdb/schema.rb
に記載され、加えてバリデーションやメソッドを追加する際に、app/models/xxx(モデル名).rb
に追加で書き込む流れのようです- Djangoではカラム情報等を確認する際モデルから見ることが多いためこの辺は少し慣れが必要そうと感じました
- Djangoではカラム情報等を確認する際モデルから見ることが多いためこの辺は少し慣れが必要そうと感じました
-
Djangoではmodel.pyが起点のため、マイグレーションの際は、model.pyに書込後→
python manage.py makemigrations
&python manage.py migrate
という流れで操作します
Railsではrails generate model
でまずファイルを作成して、必要ならば追加で情報書込み後rails db:migrate
という流れのようです- Railsを触ってみて、まずここにDjangoとの違いを感じました
Railsではrailsコマンドで基本的なカラム定義とファイル作成を自動で行ってくれるところに利便性を感じました
- Railsを触ってみて、まずここにDjangoとの違いを感じました
3.Controller(View)
※以下RailsについてはContoller、DjangoについてはViewと表記します
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)})
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'
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ディスパッチャから来る引数を明示 ②引数の明示なし |
-
Djangoではobjectsというマネージャークラスを通してデータベースクエリ操作が行わるため、記法は
Model.objects.method()
という形になります。
RailsではModel.method()
という形のようです。- objectsを記載しなくていい分、記載量が減るのでシンプルに書けそうです。
Djangoでまれにマネージャークラスでカスタムすることがあるので、どちらの設計のほうが扱いやすいかは要検証
- objectsを記載しなくていい分、記載量が減るのでシンプルに書けそうです。
-
特になし
-
DjangoではTempleteの作成は別途個別で行う必要があります
RailsではRails generate controller
でコントローラ生成の際に、app/views
以下に自動作成してくれます- Railsでは
app/views
以下にコントローラ名でフォルダ分けしながら自動作成してくれることで、ビューの作成場所・ファイル名に悩むことなく一貫したファイル管理ができる工夫があると思いました。
Djangoの汎用クラスビューではデフォルトでは<app name>/<model name>_xxx.html
といったファイル名が設定されていますが、テンプレートファイルはテンプレートフォルダ以下にまとめることが多いと思われるため、デフォルトで使用することは少なく、テンプレート保管場所・ファイル名の決定がこちらにあるのは、慣れてないうちは管理が煩雑になりやすい・ファイル作成の手間がかかるかなあという印象です。
- Railsでは
-
Djangoではテンプレートへのレンダリングをする記法は関数またはクラスのどちらかで書くことができます。関数で書く場合には、第1引数にrequestオブジェクト・それ以降にURLパラメータから来る引数を明示する必要があります(ただ実際にはDjangoのフレームワークを活用する場合は汎用クラスで書くのが基本になると思います)
Railsでは基本クラスで記述し引数の明示はなく、URLパラメータから来る引数は[:xx]
の形で受け取ります- (おそらく)Ruby/Pythonの言語仕様からくるものかと思いますがRubyのほうが記述量は少ないですね
4.View(Templete)
※以下RailsについてはView、DjangoについてはTempleteと表記します
<html>
<ul>
{% for user in users %}
<li>
<a href="{% url 'detail' user.id %}">{{ user.name }}</a>
</li>
{% endfor %}
</ul>
</html>
<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による名前空間 |
-
特にコメントなし
-
特にコメントなし
-
DjangoではURLに対応した名前空間をルーティングにて設定(ルーティング部分の
name='detail'
の箇所)し、テンプレートにてaタグ内のhref属性に{% url 'detail' %}
及び渡したいパラメータuser.id
を渡すことでリンクを設定します
Railsはlink_to
ヘルパーにモデルオブジェクトuser
を渡すことでリンクを設定します- これはRailsの方がとてもシンプルだと感じました
5.ルーティング
from django.urls import path
from views import user
urlpatterns = [
path('user', user.index, name='index'),
path('user/<int:id>', user.detail, name='detail'),
]
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.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で分岐させる |
-
Djangoでは
<int
:
arg>
で構成されます。arg>
で変数名を既定し、<int
の部分はパスコンバータと呼ばれ、URLパスのこの部分に一致するパターンを決定するコンバーターのようです(URLディスパッチャー周りについてはまだ未調査・・)
Railsでは:arg
と書きます -
特にコメントなし
-
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