CakePHP使いがDjangoでサイトを作ってみた 〜テンプレートが不要な場合〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
htmlなんていらんかったんや

この記事を三行にまとめると

HttpResponse
JsonResponse
htmlファイルなんていらんかったんや
ウェブサイトの仕様によってはページが不要な場合も出てきますよね。この場合のページってのはHTML的な、画面に表示するものという意味です。例えばAPIの開発をしていて、画面は出力せずにJSONデータを返すだけの場合とかはHTMLは必要ありません。

CakePHPだと「$this->autoRender = false」などでテンプレートの読み込まないようにできますが、Djangoでテンプレートを読み込まないためにはどうするか。僕が自分で試した限りでは主に二パターンのやり方があるので、ざっと見ていきたいと思います。



HttpResponse

一つはHttpResponseです。テンプレートを読み込まずにビューからプレーンなテキストなどをそのまま画面に出力することができます。

#views.py
from django.views.generic import TemplateView
from django.http import HttpResponse

class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return HttpResponse('hello world')

これで画面上に「hello world」が出力されます。引数に何も与えなければ何も出力しないようにできます。

class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return HttpResponse()



JsonResponse

もう一つはJsonResponseです。Jsonという単語が入っている通り、こっちはJSONデータを返すのに使えます。AjaxなどでJSONデータを受け取りたい場合はこっちを使う方が便利かもしれません。

#views.py
from django.views.generic import TemplateView
from django.http import JsonResponse

class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return JsonResponse({'text': 'hello world'})

こんな感じですね。辞書データをJSONに変換して出力してくれます。

HttpResponseでもJSONデータを返すことはできなくはないですが、HttpResponseの場合は受け取る側でちょいとデータをいじらないといけない。

JsonResponseの場合はそのままJSONデータとして扱えます。

#ビュー
class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return JsonResponse({'text': 'hello world'})

#テンプレート
$.ajax({
  'type': 'GET',
  'url': '/hello'
}).done(function(response){
  console.log(response);
  console.log(response['text'])
});

#出力結果
{'text': 'hello world'}
hello world

これがHttpResponseだと同じような出力結果にならない。

#ビュー
class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return HttpResponse({'text': 'hello world'})

#テンプレート
$.ajax({
  'type': 'GET',
  'url': '/hello'
}).done(function(response){
  console.log(response);
  console.log(response['text'])
});

#出力結果
text
undefined

HttpResponseは基本的には文字列を返すので、辞書データを渡してもそのまま文字列として出力されてしまいます。だからAjax側でresponse[‘text’]とやってもundefinedになってしまう。

HttpResponseでJSONデータを受け取りたい場合は、例えばeval()を使って文字列をJSONデータとして扱えるようにするとかですかね。

#ビュー
class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return HttpResponse("{'text': 'hello world'}")

#テンプレート
$.ajax({
  'type': 'GET',
  'url': '/hello'
}).done(function(response){
  response = eval("("+response+")")
  console.log(response);
  console.log(response['text'])
});

#出力結果
{'text': 'hello world'}
hello world

HttpResponseで辞書データをクォーテーションで囲っていったん文字列にして、javascript側でそれを再びJSONに戻すみたいな処理を行っています。これならJSONデータとして扱えます。でもこれを毎回やるくらいならおとなしくJsonResponseを使った方が効率良いっすよね。

ちなみにJsonResponseの方は文字列を渡すとエラーになってしまうので注意が必要です。

#views.py
class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return JsonResponse('hello world')

これだとエラーになる。それから辞書データではなくリストデータを渡す場合はsafeをFalseにする必要がある。

#views.py
class hello(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = super(cooperation, self).get_context_data(**kwargs)
    return JsonResponse(['hello world'], safe = False)

safeの初期値はTrueですが、Trueの場合は辞書データじゃないとエラーになるみたいです。






正直、Djangoでサイトを作っててしばらくはこのやり方に気づきませんでした。CakePHPでautoRenderをfalseにするのと同等の機能を実装するにはどうしたら良いんだと思って、render関数の第二引数にFalseを渡してみたりもしたんですけど上手くいかず、とりあえずは中身が空の「none.html」とJSONだけを出力する「json.html」っていうテンプレートファイルを作ってそれで対応してました。でも本当はhtmlファイルなんていらんかったんや。何でもしっかり調べるって大事なんですね、やっぱり。

#ビュー
class none(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = self.get_context_data(**kwargs)
    return render(request, 'none.html', context)

class json(TemplateView) :
  def get(self, request, *args, **kwargs) :
    context = self.get_context_data(**kwargs)
    context['json'] = json.dumps([1,2,3,4,5])
    return render(request, 'json.html', context)

#テンプレート(json.html)
{{json}}

これでもサイトは正常に動くんで問題ないっちゃないんですけど、でもHttpResponseやJsonResponseを使った方がスマートかなあとは思いました。
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください