読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Django ~ Django REST frameworkを使ってみる

概要

Django REST frameworkを使って、Todoアプリを作ってみる。Qiitaの参考サイトをそのままやっています。めっちゃわかりやすい。

参考サイト

qiita.com

必要なパッケージのinstallと、djangoプロジェクトの下準備

  • パッケージのinstallなど
$ pip install django
$ pip install djangorestframework
$ django-admin.py startproject django_rest_todo
$ python manage.py migrate
$ python manage.py createsuperuser
$ django-admin.py startapp api # api用のappを作成しておく
  • settings.pyを修正する。
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'api',
]

MIDDLEWARE = [
    # 'django.middleware.security.SecurityMiddleware',
    # 'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    # 'django.contrib.auth.middleware.AuthenticationMiddleware',
    # 'django.contrib.messages.middleware.MessageMiddleware',
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

なぜ、CommonMiddleware以外をコメントアウトするかが不明。。。

APIの作成とmigrate

  • models.pyにコードを追記
from django.db import models

# Create your models here.
class Todo(models.Model):
    text = models.TextField()
  • migrateする
python manage.py makemigrations
python manage.py sqlmigrate api 0001
python manage.py migrate

今まで、sqmigrateってやってなかったんだけで重要ぽいな。。特に初回。 こちらが参考になりました!

【django】マイグレーションツールの使い方 | 遍歴プログラマ日記

リアライザの作成

モデルをJSONマッピング(変換)するシリアライザを定義する。

api/serializers.py

from .models import Todo
from rest_framework import serializers # serializersをimportする。

# serializersの、HyperlinkedModelSerializerを継承したclassを作成する。
class TodoSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Todo
        fields = ('id', 'text')

views.pyにて、REST用のビューを作成する。

  • api/views.pyを定義する。
from django.shortcuts import render

from rest_framework.viewsets import ModelViewSet # ModelViewSetをimportする。
from .models import Todo
from .serializers import TodoSerializer # 先ほど定義したTodoSerializerclassを使う。

class TodoViewSet(ModelViewSet):
    queryset = Todo.objects.all()#querysetは、Todo.objectsのインスタンス
    serializer_class = TodoSerializer#serializer_classを定義する。
  • ModelViewSetは、A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as .get() or .post(), and instead provides actions such as .list() and .create().とのこと。つまり、listとかcreateとかのアクションを持つCBVのことらしい。(get, postは無いので、フォームはできないのかな。)参照サイトは以下の通り。

Viewsets - Django REST framework

APIルーティング

  • APIを処理できるようにルーティングの設定をする。ルーティングというのは、多分urlのルートを設定するということかな。urls.pyを修正する。
from django.conf.urls import url, include #includeを追記
from rest_framework.routers import DefaultRouter
from api import views # apiappのviewsをimportする。
from django.contrib import admin

router = DefaultRouter()#DefaultRouter classのインスタンスをrouterに代入する。
router.register(r'todos', views.TodoViewSet)#これは、todos/に、views.TodoViewSetをルートするという意味だと思う。

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include(router.urls)),#router.urlsをincludeする。
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),#api-authには、rest_framework.urlsをincludeする。
]

これはちょっとコツをつかむまで時間かかりそうやな.

  • routingは、rest_frameworkの、routersの、DefaultRouter classなどを利用する。
  • routerなどのような変数に、DefaultRouter()のインスタンスを代入して、それを使ってurlを設定する。
  • DefaultRouter().registerメソッドで、url名と、viewを定義する。これにより、DefaultRouter().urlsに、registerメソッドで定義されたルートが定義される。
  • DefaultRouter().urlsをincludeすることで、djangoapiのルーティングが可能になる。

フロントエンドの作成~静的ファイルの設定

  • setting.pyに追記する。
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)
mkdir static

HTMLファイルを作成する。

  • 多分、これはangular1 + bootstrap で書かれてると思う。
<!doctype html>
<html ng-app="djangoTodo">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Django REST framework Todo App</title>

    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
    <style>
        html                    { overflow-y:scroll; }
        body                    { padding-top:50px; }
        #todo-list              { margin-bottom:30px; }
    </style>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
    <script src="core.js"></script>

</head>
<body ng-controller="mainController">
    <div class="container">

        <div class="jumbotron text-center">
            <h1>Todoリスト <span class="label label-info">{{ todos.length }}</span></h1>
        </div>

        <div id="todo-list" class="row">
            <div class="col-sm-4 col-sm-offset-4">

                <div class="checkbox" ng-repeat="todo in todos">
                    <label>
                        <input type="checkbox" ng-click="deleteTodo(todo.id)"> {{ todo.text }}
                    </label>
                </div>

            </div>
        </div>

        <div id="todo-form" class="row">
            <div class="col-sm-8 col-sm-offset-2 text-center">
                <form>
                    <div class="form-group">

                        <input type="text" class="form-control input-lg text-center" placeholder="Todoを入力してください" ng-model="formData.text">
                    </div>

                    <button type="submit" class="btn btn-primary btn-lg" ng-click="createTodo()">追加</button>
                </form>
            </div>
        </div>

    </div>

</body>
</html>

JSファイルを作成する。

var djangoTodo = angular.module('djangoTodo', []);

function mainController($scope, $http) {

    $scope.readTodos = function() {
        $http.get('/api/todos/') //ここで、todosのviewにアクセスしてdjagnorestframeworkで読み込む。
            .success(function(data) {
                $scope.formData = {};
                $scope.todos = data;
                console.log(data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

    $scope.createTodo = function() {
        $http.post('/api/todos/', $scope.formData)//ここで、todosのviewにアクセスしてdjagnorestframeworkを通じて追加する。
            .success(function(data) {
                console.log(data);
                $scope.readTodos();
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

    $scope.deleteTodo = function(id) {
        $http.delete('/api/todos/' + id + '/')//ここで、todosのviewにアクセスしてdjagnorestframeworkを通じて削除する。
            .success(function(data) {
                console.log(data);
                $scope.readTodos();
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

    $scope.readTodos();

}

リダイレクトさせる。

  • index.htmlにリダイレクトするように設定する。これは地味に重要だな!これでajaxのtodoリストが可能になるのか!すごい!
from django.conf.urls import url, include #includeを追記
from django.views.generic import RedirectView
from rest_framework.routers import DefaultRouter
from api import views # apiappのviewsをimportする。
from django.contrib import admin

router = DefaultRouter()#DefaultRouter classのインスタンスをrouterに代入する。
router.register(r'todos', views.TodoViewSet)#これは、todos/に、views.TodoViewSetをルートするという意味だと思う。

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include(router.urls)),#router.urlsをincludeする。
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),#api-authには、rest_framework.urlsをincludeする。
    url(r'^todo/', RedirectView.as_view(url='/static/index.html')),
]

なるほど!!これは便利やな!!後何個かやってみよう。 angularすごいな!