Edited at

Rails以外全くわからないマンがDjangoに触れてみて驚いたRailsとの違い

More than 1 year has passed since last update.


はじめに

Ruby on Railsといえば、言わずと知れたRuby製のWebフレームワークですよね。様々なスタートアップで採用されており、世界で最も人気のあるWebフレームワークの一つと言っても過言ではありません。私はこの一年、ほとんどこのRailsのみを使って開発をしてきました。

一方で、このRailsとよく対比されるのがPython製のWebフレームワーク、Djangoです。こちらも非常に人気があり、初心者向けにDjangoとRailsを比較したインターネット上の記事なども多く見受けられます。

こちらは自分には縁のないもの、と勝手に私は思ってきたのですが、先日から縁があって知人のDjangoプロジェクトをお手伝いしています。「RailsわかるならDjangoもわかるよ!」と言われて軽い気持ちで手伝い始めたのですが、触ってみると思った以上に違うところがたくさんありました。今回はその中の一部をご紹介したいと思います。(あくまで多少触って見ての感想です。「もっと本質的な違いがある!」、「そこは実は違いではない」などありましたら教えていただけると嬉しいです。)


DjangoのRailsとの違い


Pythonファイルmanage.pyから各種コマンドを呼び出す

Railsには、シェル上で実行できるrailsコマンドがついて来ます。これを使って開発にまつわる様々な作業を行います。例えば、

rails server

でサーバーを立ち上げたり、

rails db:migrate

でマイグレーションファイルの内容をDBに反映したりできるわけです。

一方Djangoでは、プロジェクトを作成すると直下にmanage.pyという以下のようなファイルが作られます。

#!/usr/bin/env python

import os
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)

pythonを書いたことがない方でも、execute_from_command_lineといういかにもなものにコマンドライン引数を詰め込んで実行しているのがなんとなくわかっていただけるかと思います。

これによって、例えばサーバーを立てるのは

python manage.py runserver

マイグレーションファイルの反映は

python manage.py migrate

で行います。

私は開発を始めた時、当たり前のようにDjangoにもdjangoコマンドがあるものだと思い、それを呼び出そうとしていました。一つのpythonファイルを実行すると知った時、非常に不思議な感じがしたのを覚えています。些細な違いではありますが、Railsに慣れた私にとっては非常に驚きでした。


デフォルトで管理サイトがついてくる

Webアプリケーションで、開発用DBに自由なデータを入れたり、あるいは本番環境で不要なデータを消去したりしたくなることがあります。そんな時に欲しいのが、特別な権限を持つユーザーのみがアクセスでき、自由にデータの作成・更新・削除ができる管理者用画面です。

Railsには、デフォルトで用意されている管理者用画面がありません。必要な人は、自分で作成するかそれ用のgemを導入する必要があります。

一応、ActiveAdminというgemは非常に普及しており、割と簡単に管理画面の作成が可能です。しかし私は、新たなgemを入れることになんとなく敷居の高さを感じたこと、個人で作ったプロジェクトにそこまで幅広く使われたものがなかったこと(悲しい・・・)から、管理画面を導入せずにごまかしていました。

Djangoには、標準で管理サイトという機能が入っています。このページ(はじめての Django アプリ作成、その2)に詳しく載っていますが、非常に簡単な手順でモデルの作成・更新・削除が行える以下のようなページを作成できます。

admin05t.png

今まで私は一生懸命コンソールを叩いてデータの追加等を行なっていたので、この使いやすさには感動しました。それと同時に、今までActiveAdminを食わず嫌いしていたことを非常に反省したのでした・・・


MVCモデルならぬMTVモデルで作られている

Webフレームワークに触れたことのある人で、MVCモデルという言葉を聞いたことのない人は少ないでしょう。アプリケーションを、ビジネスロジックを実行するModel、ユーザーに表示される部分を描画するView、そしてその二つを繋ぐControllerに分割する考え方で、昔から多くのフレームワークがこの考え方に則って作られています。

Railsも例外ではありません。Controllerがリクエストを受け取り、Modelで諸々の処理を行い、結果をViewに詰めてユーザーに見せます。

Djangoで使われているのはこのMVCモデルではなく、MTVと呼ばれる、Model、Template、Viewからなるモデルです。と言っても、その実情はMVCモデルとほとんど変わりありません。Viewがリクエストを受け取り、Modelで諸々の処理を行い、結果をTemplateに詰めてユーザーに見せます。

ここでややこしいのは、Viewの役割が二者で全く異なることです。すごく簡単に言うと、RailsでいうViewはDjangoでいうTemplate、DjangoでいうViewはRailsでいうControllerです。大事なことなのでもう一度言います。RailsでいうViewはDjangoでいうTemplate、DjangoでいうViewはRailsでいうControllerです。本当にややこしい・・・


HTMLテンプレートに埋め込める言語はpythonではない

内部の処理に応じて描画するHTMLを変えるために、多くのWebフレームワークではユーザーに表示するHTMLにサーバーサイドで使われている言語が埋め込めるようになっています。

Railsでそれを実現する方法のうち、もっともメジャーなものがerbファイルです。比較的直感的にrubyコードをViewの中に埋め込むことができます。

例えば、Railsプロジェクト内で3の倍数番目のpタグだけ「アホ」と表示するようなファイルを作ってみましょう。

<% for i in (1..10) %>

<% if i % 3 == 0 %>
<p>アホ</p>
<% else %>
<p>賢い!</p>
<% end %>
<% end %>

すると、以下のようにしっかり描画されます。

スクリーンショット 2018-08-06 1.41.34.png

では、同じことをDjangoでやってみるとどうでしょうか。pythonの文法とDjangoのテンプレートファイルの書き方に従って、同じことをやろうとすると下のようになるでしょう。

    {% for i in range(1, 11) %}

{% if i % 3 == 0 %}
<p>アホ</p>
{% else %}
<p>賢い!</p>
{% endif %}
{% endfor %}

TemplateSyntaxError at /account/teacher/history/

'for' statements should use the format 'for x in y': for i in range(1, 11)

おっと、これを描画しようとするとエラーが出てしまいました。pythonの構文として間違いはなさそうなのになぜでしょうか。

その理由は、Djangoで描画されるTemplateに埋め込まれる言語がpythonではなく、Django テンプレート言語と呼ばれる「pythonっぽい」言語であることです。

Djangoテンプレートで利用できるのは、埋め込まれた変数と、タグと呼ばれる非常に限られた関数のみです。

組み込みタグ/フィルタリファレンス

それ以外のpython組み込み関数などは全て使えません。上のテンプレートで言えば、 range関数と%演算子はDjangoテンプレート上で利用することはできないのです。

ではどうするのか。解決手段としては、


  • View中で変数に情報を詰め込む

  • 新しいタグを自作する

のふた通りが考えられます。(そうです。Djangoではタグを自作することができます。詳しくは次のリンクを参照してください。テンプレートタグやフィルタを自作する

この例で言えば、まずrange(1, 11)をView内で行って変数numbersに入れます。また、引数が3の倍数であればアホ、そうでなければ賢い!を返すタグnabeatsuを定義します。その上で、

    {% for i in numbers %}     

<p>{{ i | nabeatsu }}</p>
{% endfor %}

このように記述すれば同じ結果を得ることができます。

Railsでの開発では、私は割とView内で自由にrubyコードを書きがちだったので、初めてDjango テンプレート言語に触れた時は思うような実装ができずやきもきしました。しかし、思い出していただきたいのはMVCにおけるViewの役割です。Viewは情報をユーザーに見せるところ。ロジックをゴリゴリ書くところではないのです。

Djangoの公式ドキュメントには、以下のような記述があります。


プログラミングの知識があったり、 PHP のようなプログラムコードを直接 HTML に混ぜ込む言語を使ったことがあるなら、 Django のテンプレートシステムが単に HTML に Python を埋め込んだものでないことに疑問を持つでしょう。 しかし、これは設計上意図して決まっていることです。テンプレートシステム はプレゼンテーション層を表現するためのもので、プログラムロジックではないのです。


http://djangoproject.jp/doc/ja/1.0/topics/templates.html

Djangoは設計意図によって、「よくない」書き方を多少過激に抑制しているのです。

その事実を突きつけられて自分のコーディングの仕方を反省する反面、やはりRailsのViewの自由さにも良さを感じてしまう自分もいます。


最後に

私は今でもRailsが大好きです。しかし、ちょっと趣の違うDjangoに触れることで、Railsならではの要素がどこにあるのかを感じたり、自分がRailsを使うスタイルを反省したりと、様々な学びを得ることができました。Railsの使い心地がよく、離れられないという皆さんも、ちょっとだけ他のフレームワークに浮気してみませんか?