世界を動かす技術を、日本語で。

Djangoの使い始めに関するいくつかのメモ

概要

  • Django を学び始めた体験のまとめ
  • Rails や他フレームワークとの比較
  • Djangoの強み (明示性・管理画面・ORMなど)の紹介
  • SQLiteの活用 や設定ファイルの悩みについても言及
  • 今後さらに Djangoの機能 を学ぶ意欲

Djangoを学び始めて感じたこと

  • 古くて枯れた技術 を学ぶ楽しさ ・20年以上使われている技術の安心感 ・過去の問題がすでに 解決済み で、すぐに作業できる利便性

  • Djangoを選んだ理由 ・RailsやLaravelにも興味があったが、DjangoでWebサイト作成を開始 ・数ヶ月使ってみて、 明示的で分かりやすい構造 に好印象

Railsとの比較:Djangoの「魔法の少なさ」

  • Rails は「魔法」が多く、久しぶりに触ると 構造を思い出すのが大変 ・例:routes.rbのresources :topicsだけではルートの詳細が分かりにくい ・Djangoは主要ファイルが明確で、プロジェクト放置後も 復帰しやすい

  • Djangoの主なファイル構成 ・urls.py, models.py, views.py, admin.py, tests.py ・HTMLテンプレートも 明示的に参照 されていて追いやすい

標準搭載の管理画面(Admin)

  • Djangoの管理画面 はデフォルトで強力 ・少しのコード追加で カスタマイズ可能 ・例:list_display, search_fields, orderingなどを簡単に設定

ORMの楽しさ

  • 以前は「SQL直書き派」だったが、 DjangoのORM が便利で楽しい ・__(ダブルアンダースコア)で JOINを表現 できる直感的な記法 ・複雑なクエリも 可読性が高く簡潔 ・パフォーマンスも問題なく、現状は ORMに満足

自動マイグレーション

  • models.py の変更に応じて 自動でマイグレーションファイル生成 ・生成されたスクリプトをそのまま使えて 運用が楽 ・データモデルの頻繁な変更にも 柔軟に対応

ドキュメントの質の高さ

  • これまで ドキュメントを読まない癖 があったが、Djangoの公式ドキュメントは 非常に分かりやすい ・Jacob Kaplan-Mossによるドキュメント文化の講演も存在 ・modelsのイントロなど、 必要な情報が整理されている

SQLiteの活用

  • Postgres運用でのトラブル経験から SQLite を選択 ・小規模サイトなら VACUUM INTO で簡単バックアップ ・DjangoでのSQLite運用方法も 公式手順 に従って問題なし ・1日数百件程度の書き込みなら 十分に実用的

バッテリー同梱主義(Batteries-included)

  • CSRF対策Content-Security-Policy、メール送信など 標準搭載 ・開発環境では メール送信をファイル保存 に切り替える設定も簡単 ・本番環境用のSMTP設定も 設定ファイル分割で管理

設定ファイル(settings.py)の悩み

  • settings.py はグローバル変数を手動で設定するため、 タイプミスが不安 ・例:WSGI_APPLICATOINと書いても エラーに気付きにくい ・Python言語サーバーによる 補完やエラー検出が効かず、やや不安

今後の展望

  • これまで 本格的なWebフレームワーク経験が少なかった ため、今後の学びに期待 ・Djangoの フォーム検証や認証機能 など、まだ未学習の部分が多い ・Marco Rogersに ORMの良さを教えてもらったことに感謝 ・今後も Djangoの新機能や活用法 を探求していく予定

コメント・フィードバック募集

  • Mastodon上で コメント受付中 ・「あなたのお気に入りのDjango機能」をぜひ教えてほしい

Hackerたちの意見

プロジェクトにはいつもDjangoに戻っちゃうんだ。めっちゃ素晴らしいよ。付属してる機能が十分にあって、すごくパワフルなんだ。

Djangoは、ウェブアプリケーション開発において、俺が今まで触ってきた中で最も生産的な「退屈な技術」だと思う。毎回のリリースで派手な機能を追加するわけじゃないけど、安定性を保っていて、過去のバージョンとの互換性もちゃんとあるんだよね。

Djangoの話は置いといて、これはすごく大事なポイントだと思う。プロジェクトを数ヶ月や数年放置して、また戻ってこれるっていうのは、俺にとってすごく重要なんだ(これが俺のプロジェクトのやり方!)。趣味でやる場合は特にそうだけど、大きな環境でも、XYZの仕組みを理解してる人を常に確保するコストがあるし、新しい人を育てるのも大変だよね。俺も、過去の自分とのやり取りが、良い習慣を学ぶのに役立ってるって感じてる。これが仕事にもプラスになってるんだ。

これが、私が個人プロジェクトに自動テスト(CIで実行するように設定)とちゃんとしたドキュメントを確保することにめちゃくちゃ厳格な理由なんだ。時間が経ってほとんど忘れちゃったときに、また取り組むのがすごく楽になるからね。

「冷血ソフトウェア」っていう表現、めっちゃいいね。https://dubroy.com/blog/cold-blooded-software/ (HN: https://news.ycombinator.com/item?id=46488261)

だから、私は小さな使い捨てプロジェクト以外は、正式な要件文書を書くようにしてるんだ。18ヶ月前に何を考えてたかを知るのがずっと楽になるから、当時の考えを書き留めておくのが大事だよ。

VACUUM INTOを使ってバックアップできるのが好きだし、その結果できたファイルをコピーするだけで済むんだ。素直に考えると、sqliteファイルをそのままコピーしちゃうかも。これって悪いアイデア?

VACUUM INTOコマンドについては、sqliteデータベースのバックアップ方法に関するガイドで学んだよ: https://litestream.io/alternatives/cron/

SQLiteが動いてないならそれでいいけど、ファイルが書き込み中のときにコピーすると破損のリスクがあるよ。VACUUM INTOを使うと、そのリスクがなくなるんだ。

DjangoのORMやマイグレーションは、幸福度の面でまだまだ無敵だね。

こんなに長い間経っても、Djangoみたいなマイグレーションがどの言語にもないのが信じられない。見た目はすごくシンプルでパワフルなのに、自動生成するには何か複雑なことがあるんだろうな。ElixirやRustに行ったとき、マイグレーションの話がもっと複雑で手動だったのには驚いたよ。ただモデルを変えてマイグレーションを生成してコミットするだけなのにね。LLMが普及する前は、ectoファイルを書いてたけど、Djangoに比べて大きなデータベース構造を定義するのがすごく繰り返し作業だった。

自動マイグレーションには本当にビビる。ElixirやEctoみたいにスキーマやマイグレーションを自分で書く方が好きだな。それに、同じテーブルに対して2つの異なるスキーマを持つオプションがあるのもいい(使わないけど)。

Railsを試したことある?Djangoのアプローチは、Railsからの適応だと思うよ。

ダウンタイムなしでCDをどうやるかが全然わからなかった。フィールドを追加・削除したいときは特別な手順が必要で、新しいコードと古いコードが新しいスキーマと古いスキーマの両方で動くことを確認しなきゃいけない。私が見つけた回避策は、スキーマ変更があるときにCIで新しいスキーマ+古いコードのテストを実行してから、新しいコードをデプロイする前にmakemigrationsを実行すること。もっと良いパターンはないのかな、「気をつければ大丈夫」っていうのはちょっと物足りないよね。

Djangoを8年間使ってきたけど、他のものに移るのが難しいな。ちょうどいい魔法感と柔軟性があって、作業するのが本当に楽しい。DjangoはシンプルなCRUDには向いてるけど、複雑なものには弱いっていうのは全然違うよ。500億円の評価を受けている会社でDjangoのモノリスを使って働いていたけど、レポート、レコメンダーシステム、ファイル取り込みパイプライン、LLMエージェントによる自動ファイルタグ付けなど、すべてDjangoアプリの中でうまくつながってる。Djangoアプリだからって、基本的なHTTPリクエスト処理以外のライブラリを使ったり、他のことをするのができないわけじゃないよ。最近、FlaskとSQLAlchemyをバックエンドに、Reactをフロントエンドに使ったクラシックなSPAプロジェクトで契約する不運に見舞われたけど、フォームにフィールドを追加するのに必要なコードの量には驚いたよ。

最近、FlaskとSQLAlchemyをバックエンドに、Reactをフロントエンドに使ったクラシックなSPAプロジェクトで契約する不運に見舞われたけど、フォームにフィールドを追加するのに必要なコードの量には驚いたよ。私も同じだよ。Flask + SQLAlchemy + Reactを使った理由は、シンプルなツールだからで、Djangoは複雑なツールだからね。特にFlaskの部分は、Djangoにすでに含まれている管理、フォーム、テンプレート用のプラグインを使いこなすのが大変だった。でも、Flaskはシンプルなサイト向けに作られてるから、コーディングやメンテナンスは楽だと思うよ。

Re: DjangoはシンプルなCRUDにはいいけど、複雑なものには向かないかも。 もしかしたら、複雑なアプリケーションでDjangoを使った経験が影響してるかもしれないけど、逆に思っちゃうんだよね。シンプルなCRUDにはオーバーキルな気がするけど、使うのは大好きなんだよね。

アプリ同士は「どうやって繋がる」の?私の経験では、気をつけないとDjangoのモノリスはすぐに大混乱になっちゃう。最近、これを解決するためにTachを使い始めたところだよ。

Frank Wiles(RevsysのDjangoコンサルタント)からのDjangoのおすすめがいくつかあるよ: https://frankwiles.com/questions/starting-django-projects/ 私のおすすめもいくつか追加するね。* uvを使ってプロジェクトをセットアップする * Djangoプロジェクトを「project」と名付ける;設定はproject/settings.py、メインのURLはproject/urls.py、など * 余計なものがまだ必要なくても、カスタムDjangoユーザーモデルを必ず定義する;後で拡張しやすいから * settings.pyはプロジェクトの設定(Djangoアプリ、ミドルウェアなど)とインスタンス/環境設定(データベースアクセス、ストレージ、メール、認証など)が混在している;プロジェクト設定はハードコーディングして(環境間で変わらないから)、python-dotenvを使って環境/.envから設定を引き出す;すべての設定可能な変数を.env.exampleにドキュメント化して、デフォルトはローカル/開発セットアップに適している(DEBUG=true、SQLiteデータベース、ALLOWED_HOSTS=*、ランダム生成のSECRET_KEYなど);あ、DATABASE_URLを使うためにdj-database-urlも使ってる(デフォルトはsqlite:///sqlite.db) * すぐにruff、ty、pytest、pre-commitフック、GHワークフローをセットアップしてruff/ty/pytestを実行するようにする。以前は複雑なスキャフォールディング/スケルトンテンプレートを使ってたけど、今は小さなシェルスクリプトを使って、Claudeに上記の指示に従ってsettings.pyを適応させるようにしてる :)

ひとつ追加するね。shell_plusを入れると、Djangoのシェルがすごく使いやすくなるよ。特に大きなプロジェクトではね(モデルを自動でインポートしてくれるから)。確か、ipythonとdjango_extensionsを依存関係として追加して、django-extensionsをインストールアプリに加える必要があるんだ。面倒なのは、アンダースコアがダッシュに変わること。これ、毎回引っかかるんだよね。でも、django-extensionsはshell_plus以上のことをたくさんやってると思うから、今度その機能も探ってみようかな。編集:bpythonやptpython、あるいはshell_plusなしでも使えるみたいだから、ipython以外が好きな人にはいい情報だね。

環境/.envから設定を引っ張るためにpython-dotenvを使う。 これには強く反対だな。結局、設定を別のファイルに移してるだけじゃん。共通の設定を読むローカル設定ファイルを使った方がいいよ。プロダクションでは、秘密にしておくべきAPIキーなどは、プロジェクトディレクトリの外に置いて、別のユーザーが所有するようにするのが最低限のルールだね。

  • settings.pyは実際にプロジェクト設定(Djangoアプリ、ミドルウェアなど)とインスタンス/環境設定(データベースアクセス、ストレージ、メール、認証など)を混同している。プロジェクト設定はハードコーディングして(環境間で変わらないから)、python-dotenvを使って環境/.envから設定を引っ張る。すべての設定可能な変数は.env.exampleに文書化して、ローカル/開発環境のデフォルトは理にかなっている(DEBUG=true、SQLiteデータベース、ALLOWED_HOSTS=*、ランダム生成されたSECRET_KEYなど)。それと、DATABASE_URLを使うためにdj-database-urlを使ってる(デフォルトはsqlite:///sqlite.db)。異なる環境用に「foo_settings.py」を作成して「settings.py」の隣に置く慣習があって、「from .settings import *」で始める。秘密のためには別のものが必要だけど、これで他のすべてのこと、特にオーバーライドを含む理にかなったデフォルトがうまく機能するよ(基本ではDEBUG=Falseで、適切なものだけでTrueにする)。

いいね。15年間ほぼDjango開発者としてやってきて、最近またFastAPIやいろんなORMに触れたから、Djangoのことについてドキュメントを書いてみようかな。Djangoは結構いい感じで、バージョン間の変更も小さくて人間が管理できる範囲だよ。大きなエコシステムがある理由の一つは、設定やINSTALLED_APPS、ミドルウェアなどを登録するための中央の場所があるから。これがあれば、アドオンが自分のテンプレートやマイグレーションを持ってこれるんだ。manage.pyの上の方にも中央の場所があって、Djangoにコマンドラインの拡張を持ってこれるよ(インストールするものの多くはそれを持ってる)。FastAPIアプリにalembicを使って行くと、いろいろ自分で作らなきゃいけないのがちょっとショックだよね。DjangoのORMは最初はちょっと異質に感じるかもしれない。「なんでこれがsqlalchemyじゃないの?」って昔は思ったけど、APIは実際にはかなり実用的で簡単に拡張できるよ。かなり複雑なクエリも組み立てられるし、Django-Debug-Toolbarとそのクエリビューワーを使って最適化もできる。ORMやテンプレート、Djangoの他の部分は多くの新しい標準よりも前からあったから、自分たちのバージョンを持ってるんだ。Django開発者として、他の世界がテストコンテナやデータベースを発明したことを最近知ったけど、これはDjangoが何年も前にテストデータベースサポートで解決した問題の解決策だよね。設定ファイルにsettings/common.pyがあって、それを拡張する設定が好きなんだ。例えば、local.pyやproduction.pyみたいにね。もしDjangoプロジェクトにCMSが必要なら、Wagtailを強くおすすめするよ。最初に人気だったdjango-cmsの後に出てきて、多くの教訓を学んだから、Djangoの一部としての感覚が強いんだ。最初に使ったときのDjangoの生産性の感覚と同じだよ。

Django開発者として、他の世界がテストコンテナやデータベースを発明したことを最近知ったけど、これはDjangoが何年も前にテストデータベースサポートで解決した問題の解決策だよね。モデルベーカリーとpytest-djangoでAPIをテストするのは本当に楽しいよ。TDDオタクとして、FastAPIに似た開発体験がないのが、私が移行しなかった主な理由なんだ。余談だけど、エルゴノミックなテストが好きな私としては、テストコンテナはあまり良くないと思う。テスト用のDocker化されたサービスはいいけど、その管理はテストコードの外でやるのがベストだよ。特別なテストハーネスを使ってテストスイートの内部で管理するよりも、ローカルコンテナで動いてる一般的なDBやサービスのURLに接続する方が、プロダクションをエミュレートするのはずっと簡単だからね。

FastAPIアプリにalembicを使って、ほとんどが自分で作る必要がある(しかも簡単に壊れちゃう)ってのはちょっとショックだよね。ちょっとだけFastAPIを触ってみたけど、同じようなショックを受けた後にDjango-Ninjaを見つけたんだ。これはFastAPIをモデルにしてて、非同期にも対応してる(興味があればだけど、注意してね、ドラゴンがいるから)。Djangoのすべての部分、ORMも含めて、うまく連携するよ。

Djangoが何年も前にテストデータベースのサポートで解決した問題の解決策として。今では「数十年前」と言ってもいいくらいだと思う。

Djangoを始める人のために、数年前にいくつかのガイドラインを書いたよ。 https://spapas.github.io/2022/09/28/django-guidelines/ (Djangoを10年以上専ら使ってきた後にね)

これらの意見には、多くの人が賛成だし、全てに賛成かもしれない。まとめてくれてありがとう。これらはSKILL.mdに簡単に変換できるね。

Djangoは素晴らしいけど、コードの型が足りないし、特にドキュメントにおいてはね。これがあれば、もっとバグを減らせたと思う。私の意見では、型アノテーションは明らかな場合やシンプルなMVPプロジェクト以外では省略すべきじゃないよ。