HyでDjangoアプリを実装する

  • 8
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

この記事は、LISPっぽいけど一応Python その2 Advent Calendar 2015の5日目の記事です。

HyのREADMEに"Django + LISP"という一文があり、DjangoアプリをHyでも実装できるというコンセプトを示したソースコードが示されていますが、これだけでは何をどうすればいいか分からないので、startprojectするところからステップを追って解説します。

githubにレポジトリを作り、ステップごとにコミットを分けてpushしたので参考にしてください。

startprojectする

ひとまず普通のPythonでdjango-admin.py startprojectします。使用しているDjangoのバージョンは1.9です。

django-admin.py startproject hellohy

startprojectした段階のコミットがこれです。

*.py*.hyに書き換える

すべてのプログラミング言語はLISPに至るので、出来る限りPythonコードを排除して、Hyで置き換えたいと思います。

プロジェクトの作成直後のコードをHyに書き換えたコミットがこれです。

少し躓いた点は以下の2つです。

  • manage.pyをHyに置き換えても、hy manage.hy runserverが動かなかったので、このファイルだけは諦めました。
  • Hyでモジュールを定義するには、起動スクリプト(この場合manage.py)にimport hyを入れる必要があるようです。
  • シングルクォートはHy(LISP)では特殊な意味を持つので、文字列はすべてダブルクォートに変更しました。

Pythonのimport x, from y import zのHyの変換の仕方は、ここを見れば一目瞭然です。

この段階で、manage.py以外のすべてのpyファイルを消しても、python manage.py runserverが動くようになり、実際にブラウザでもアクセスできます。

app_templateを作成

startprojectの後はstartappでDjangoアプリケーション・モジュールを追加するのがDjangoの定番の流れですが、この段階でstartappしてもPythonモジュールが追加されるのは分かりきっていたので、先にアプリケーション・テンプレートを追加します。

それが、このコミットです。

このapp_templateを使ってstartappを実行します。

python manage.py startapp --template=hellohy/app_template -ehy myapp

ポイントは、

  • --templateで独自のアプリケーション・テンプレートのディレクトリを指定する。
  • -eでテンプレートとして扱うファイルの拡張子を追加する。

ことです。

上記コマンドでmyappというアプリケーションを作り、myapp.views.topというごく単純なテンプレートを表示するビューを追加したコミットがこちらです。

モデルを定義する

HyのチュートリアルにDjangoのモデルっぽいサンプルコードがありますが、この段階でそれが擬似コードではなく、実際に動くコードであるというのが確認できます。

モデルを足して、データベース上のデータを表示するようにしたコミットがこちらです。

モデルの定義は以下のようになっています。

(import [django.db [models]]
        [django.utils.timezone :as timezone])

(defclass Topic [models.Model]
  [title (models.TextField)
   url (models.URLField)
   created_at (models.DateTimeField :default timezone.now)])

Topicとは何らかのニュースのタイトルをソースのURLを表したオブジェクトと考えてください。重要なのは次の点です。

  • defclassは最新開発版のHyの構文を使っています。
  • クラスプロパティはdefclassマクロの3番目の引数にリストで与えます
  • Pythonのキーワード引数models.DateTimeField(default=timezone.now)(models.DateTimeField :default timezone.now)のように表現します。

モデルを定義した後に、makemigrations, migrateする手順は通常のDjangoと同じです。

ビューを実装する

上で定義したTopicオブジェクトを複数件取得してテンプレートをレンダリングする例です。

(import [django.shortcuts [render]]
        [myapp.models [Topic]])

(defn top [req]
  (def topics (-> (Topic.objects.all)
                  (.order_by "-id")))
  (render req "top.html" {"topics" topics}))

プライマリキーでオブジェクトを取得してテンプレートをレンダリングする例。

(import [django.shortcuts [render]]
        [django.http [Http404]]
        [myapp.models [Topic]])

(defn topic_detial [req topic_id]
  (def topic (try
              (Topic.objects.get :pk topic_id)
              (except [e Topic.DoesNotExist] (raise Http404))))
  (render req "topics/topic_detail.html" {"topic" topic}))

以下のコミットで一覧と詳細のビューを追加するところまで実装しています。

ユニットテスト

Djangoを使うことのメリットにユニットテストがしやすいということがあると思うので、今回もユニットテストを足しておくことにしましょう。

それが、このコミットです。

本当はこのtests.hyだけでユニットテストが実行できればよかったのですが、テストランナーが.hyを見つけてくれなかったので、裏技のような感じになってしまいますが、同名の空の.pyファイルを足しています。

この裏技は何とかしたいと思いますが、とりあえずテストは通っています。

$ python manage.py test myapp
Creating test database for alias 'default'...
....
----------------------------------------------------------------------
Ran 4 tests in 0.051s

OK
Destroying test database for alias 'default'...

最後に

HyでDjangoアプリを実装していく手順を紹介しました。

ご自身でも試してもらえればお分かりになると思いますが、HyでもDjangoのパワーを100%引き出せそうなので、すべてのプログラミング言語はLISPに至るというのを実感できますね。

次回はHyで書いたDjangoアプリを実環境にデプロイする方法を通じて、Hyの可能性を探っていきたいと思います。