Help us understand the problem. What is going on with this article?

Python Django入門 (6)

スマホAPIを作る

ここまで、HTMLのレスポンスを返す、Webアプリケーションの例を見てきました。

次に、iOS/AndroidアプリのバックエンドとしてJSONを返す例を作ってみます。

Django REST frameworkのように、REST APIを作るモジュールを導入することもできますが、まずは自分で書いてみることにします。

apiアプリケーションの作成

mybook プロジェクトの下に api というアプリケーションを作成します。

$ python manage.py startapp api

mybook プロジェクトのディレクトリの下に、以下のファイルが作成されました。

mybook/
    api/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
        models.py
        tests.py
        views.py

JSONを返すビュー

基本は、jsonモジュールを使って、Python辞書オブジェクトをJSONに変換します。

import json

data = {'id': 1, 'name': 'hoge'}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
  • ensure_ascii=False # 日本語が含まれる時、このように指定。
  • indent=2 # 空白2個で整形する場合。省略すると整形しない。

ただし、Python辞書は順不同になるため、JSONの中身も順不同となってしまいます。

そこで、collections.OrderedDict 順序付き辞書を使います。

なお、OrderedDictが使えるのは、Python 2.7 からなので、サーバ環境によって Python 2.6 以下の場合は、orderddictを使います。

api/views.py は以下のようになります。

import json
from collections import OrderedDict
from django.http import HttpResponse
from cms.models import Book


def render_json_response(request, data, status=None):
    """response を JSON で返却"""
    json_str = json.dumps(data, ensure_ascii=False, indent=2)
    callback = request.GET.get('callback')
    if not callback:
        callback = request.POST.get('callback')  # POSTでJSONPの場合
    if callback:
        json_str = "%s(%s)" % (callback, json_str)
        response = HttpResponse(json_str, content_type='application/javascript; charset=UTF-8', status=status)
    else:
        response = HttpResponse(json_str, content_type='application/json; charset=UTF-8', status=status)
    return response


def book_list(request):
    """書籍と感想のJSONを返す"""
    books = []
    for book in Book.objects.all().order_by('id'):

        impressions = []
        for impression in book.impressions.order_by('id'):
            impression_dict = OrderedDict([
                ('id', impression.id),
                ('comment', impression.comment),
            ])
            impressions.append(impression_dict)

        book_dict = OrderedDict([
            ('id', book.id),
            ('name', book.name),
            ('publisher', book.publisher),
            ('page', book.page),
            ('impressions', impressions)
        ])
        books.append(book_dict)

    data = OrderedDict([ ('books', books) ])
    return render_json_response(request, data)

render_json_response() はJSONP にも対応しています。
スマホのAPIだけでなく、JavascriptのAjaxでJSONを取得する場合にも応用できます。

JSONを返すURL

api/urls.py というファイルを新規作成し、以下のように記述します。

from django.urls import path
from api import views

app_name = 'api'
urlpatterns = [
    # 書籍
    path('v1/books/', views.book_list, name='book_list'),   # 一覧
]

この api/urls.py を、プロジェクトの mybook/urls.py で include します。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('cms/', include('cms.urls')),
    path('api/', include('api.urls')),  # ここを追加
    path('admin/', admin.site.urls),
]

INSTALLED_APPS への追加

api アプリケーションをインストールしたことを、プロジェクトに教えてあげる必要があります。

model も template もないので、なくても動きますが、一応やっておきましょう。

api/apps.py を開いてみると、ApiConfig というクラスが定義されています。
これを mybook/settings.pyINSTALLED_APPS の最後に 'api.apps.ApiConfig', という文字列で追加します。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'cms.apps.CmsConfig',   # cms アプリケーション
    'api.apps.ApiConfig',   # api アプリケーション
    'bootstrap4',           # django-bootstrap4
]

結果の確認

それでは、ブラウザで以下のURLを開いて下さい。

http://127.0.0.1:8000/api/v1/books/

結果は以下のようになります。

{
  "books": [
    {
      "id": 1,
      "name": "Django 入門",
      "publisher": "GeekLab.Nagano",
      "page": 100,
      "impressions": [
        {
          "id": 1,
          "comment": "あああ\r\nいいい"
        },
        {
          "id": 2,
          "comment": "ううう\r\nえええ"
        },
        {
          "id": 4,
          "comment": "コメント\r\nです。"
        }
      ]
    },
    {
      "id": 2,
      "name": "書籍2",
      "publisher": "GeekLab.Nagano",
      "page": 200,
      "impressions": []
    }
  ]
}

iOS/Androidアプリからのデータの受信

iOS/Androidアプリに対してデータを送信する場合は JSON でよいですが、データを受信したい場合はどうするのでしょうか。

  • 簡単なデータの場合は、Webアプリのフォーム受信と同じものを書いて、スマホ側では http form post を模倣してもらいます。
    • こうすることによって、データのエラーチェックは、フォームのバリデーションの仕組みが使えます。
    • 正常かエラーかは、JSONで結果を返すようにします。
  • 繰り返しがある複雑なデータは、スマホ側からJSONをPOSTしてもらい、json.loads() でデコードします。

JSONで受信する場合、request の raw_post_data からJSON文字列を取り出せます。

import json

def xxxx_post(request):
    python_obj = json.loads(request.raw_post_data)  # RequestのBodyが直接JSON文字列となるようPOSTしてもらう
      :

スマホAPIのまとめ

スマホAPIだけを作るのであれば、データ投入は Django の管理サイトの機能を使い、API部分だけを書く、といったことも可能です。

簡単にスマホのバックエンドを作成することができます。

なお、本格的にAPIを作成する場合は、Django REST frameworkの導入も検討してください。

最後に

ここまでで、この講座は終了です。

この講座の後に、公式チュートリアル その1〜7 をやってみることによって、さらに理解が深まると思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした