View on GitHub

データベースからの推薦リストの取得

Home

データベースからの推薦リストの取得

データベースから推薦リストを取得するようにしてみましょう。データベースにアクセスするためにはサーバと通信する必要があります。クライアントからリクエストデータをサーバに送信し、サーバで処理された結果をレスポンスデータとしてクライアントに返す、という処理を行うことになります。サーバと通信するための方法の一つとして、Ajaxを用いる方法があります。ここでは、Ajaxによるクライアントとサーバとの通信方法について説明します。なお、Ajaxの詳細については文献[1]を参照してください。

ここでは、ランダム推薦システムによる推薦リストを取得できるようにしてみましょう。まずは、サーバとの通信処理としてMainPage.jsMainPageクラスに下記のgetRandomRecommendations()メソッドを追加してください。

リスト1: recsys_django/static/js/MainPage.js

    /**
     * ランダム推薦システムによる推薦リストを取得する。
     */
    getRandomRecommendations() {
        let thisPage = this;
        $.ajax({
            url: 'random/',
            method: 'GET',
            data: {
            },
            timeout: 10000,
            dataType: 'json',
        }).done(function(response) {
            let description = response.description;
            let reclist = response.reclist;
            console.log(description, reclist);
        }).fail(function(response) {
            window.alert('MainPage::getRandomRecommendations() : failed');
        });
    }

getRandomRecommendations()メソッドは、サーバと通信し、サーバから推薦リストを取得した後、その推薦リストをコンソールに表示します。例えば、ブラウザがGoogle Chromeの場合、ブラウザの右上のメニューからその他のツール > デベロッパー ツールを選択するか、F12キーを押すことでデベロッパーツールが表示されます。そのデベロッパーツールからConsoleタブを開くことで、コンソールが表示されます。コンソールには、エラーメッセージなどデバッグに重要な情報が出力されます。JavaScript上では、console.log()メソッドを用いることで、コンソールにメッセージを出力させることができます。

getRandomRecommendations()メソッドにはAjaxによる通信に関するコードを記述しています。Ajaxによりクライアントとサーバが通信するためには、jQueryで提供されている$.ajax()メソッドを呼び出します。$.ajax({...})の部分はサーバに伝える情報です。.done(function(response) {...}の部分には、サーバからレスポンスデータを受け取った後に実行する処理を記述します。

サーバに伝える情報は次のとおりです。

以上の情報を指定することで、サーバにリクエストデータを送信することができます。

リクエストデータをサーバに送信した後は、サーバ側でリクエストデータに基づく処理が実行され、その結果がレスポンスデータとしてクライアントに返ってきます。

サーバ側での処理が成功した場合は、.done(function(response) {...}の部分の処理が実行されます。一方で、サーバ側で何らかのエラーが発生するなど、処理が失敗した場合は、.fail(function(response) {...}の部分の処理が実行されます。

サーバからのレスポンスデータは、responseに格納されます。この例では、dataType'json'を指定していますので、responseにはJSON形式のレスポンスデータが格納されています。今回の例では、レスポンスデータに含まれているresponse.descriptionresponse.reclistをそれぞれ変数descriptionreclistに格納しています。

つづいて、サーバ側の処理を記述します。online/views.pyに下記のRandomViewクラスを追加してください。

リスト2: recsys_django/online/views.py

import json                                 # 追加

from django.views.generic import View
from django.shortcuts import render
from django.http import HttpResponse

from .models import Item              # 追加
from .mappers import RecRandomMapper  # 追加
......
# 以下を追加
class RandomView(View):
    """ランダム推薦ビュー
    """

    def get(self, request, *args, **kwargs):
        """ランダム推薦リストを取得する。

        Parameters
        ----------
        request : WSGIRequest
            リクエスト

        Returns
        -------
        HttpResponse
            推薦説明と推薦リストをJSON形式で返す。
        """
        # オブジェクトの取得
        reclist = list(Item.objects.order_by('?'))
        recs = [RecRandomMapper(rec).as_dict() for rec in reclist]

        # レスポンスの生成
        description = '本日のおすすめ'
        response = {
            'description': description,
            'reclist': recs,
        }
        response_json = json.dumps(response)

        # レスポンスの返却
        return HttpResponse(response_json, content_type='application/json')

このRandomView.get()メソッドでは、データベースから推薦リストを取得し、それをレスポンスデータとして生成し、クライアントに返却します。

まず、# オブジェクトの取得の部分で、Item.objects.order_by('?')メソッドを用いてItemモデルからすべてのデータをランダムに並び替えて取得しています。この結果を推薦リストreclistとして受け取っています。ただし、後でこの推薦リストをJSON形式として渡しやすくするため、辞書型に変換しておきます。推薦オブジェクトを辞書型に変換するためのマッパーを定義します。recsys_django/online/ディレクトリにmappers.pyを作成し、下記のコードを記述してください。

リスト3: recsys_django/online/mappers.py

class RecRandomMapper:
    """ランダム推薦マッパー

    Attributes
    ----------
    rec : Item
        推薦オブジェクト
    """

    def __init__(self, rec):
        self.rec = rec

    def as_dict(self):
        """推薦オジェクトを辞書型として取得する。

        Returns
        -------
        dict
            推薦オブジェクトを辞書型にして返す。
        """
        item = self.rec
        return {
            'rank': 1,
            'item': {
                'item_id': item.item_id,
                'name': item.name,
                'red': item.red,
                'white': item.white,
                'shining': item.shining,
            },
            'score': 1,
        }

つづいて、RandomView.get()メソッドの# レスポンスの生成の部分では、レスポンスデータをJSON形式で生成しています。JSON形式は、{キー: 値}対の集合です。JSON形式の詳細は文献[2]などを参照してください。ここでは、推薦説明文を表す'description'と推薦リストを表す'reclist'を、それぞれキーとして定義しています。ここで、responseは厳密には辞書型になりますので、これをJSON形式にエンコードする必要があります。このエンコードにはjson.dumps()メソッドを用います。これを利用するには、jsonパッケージをインポートする必要があります。これが冒頭のimport jsonです。JSON形式にエンコードしたレスポンスデータをresponse_jsonとしています。

最後に、# レスポンスの返却の部分で、生成したレスポンスデータをクライアントに返却します。

これでサーバ側の処理が記述できました。後は、この処理がクライアント側から呼ばれるようにしましょう。まず、URLconfを設定します。recsys_django/online/urls.pyに下記コードを追加してください。

リスト4: recsys_django/online/urls.py

from django.urls import path
from . import views

app_name = 'online'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('random/', views.RandomView.as_view(), name='random'),     # 追加
]

このように、URLrandom/にアクセスされたとき、views.RandomView.as_view()が呼ばれるように設定しました。

さて、このURLrandom/にはいつアクセスされるのでしょうか。それが、リスト1のgetRandomRecommendations()メソッドの$.ajax({...})で指定したurlです。リスト1ではurlrandom/を指定していました。したがって、ここからURLrandome/にアクセスされるということになります。さらに、リスト1ではmethod'GET'を指定していました。これにより、URLrandom/にアクセスされたとき、リスト2のRandomView.get()メソッドが呼ばれることになります。

最後に、main.jsinitData()関数から、リスト1のgetRandomRecommendations()メソッドを呼び出すようにしましょう。main.jsinitData()関数に下記コードを追加してください。

リスト5: recsys_django/static/js/main.js

/**
 * データの初期化
 */
function initData() {
    currentPage = mainPage;

    // 各推薦リストの取得
    mainPage.getRandomRecommendations();
    
    currentPage.draw();
}

ブラウザで下記のURLにアクセスしてみましょう。

http://localhost:8000/

画面上は変わりありませんが、コンソールを表示してみてください。

インタフェース

コンソールに「本日のおすすめ」と推薦リストの内容が出力されていれば、データベースからの推薦リストの取得に成功です。もし、正しく出力されず、「MainPage::getRandomRecommendations() : failed」というアラートが表示された場合は、サーバ上で何らかのエラーが発生しています。サーバから出力されたエラーメッセージを参照し、デバッグしてみましょう。

参考

  1. 現場で使える Django の教科書《実践編》 # 第4章 開発のヒント(Ajax対応とJSONレスポンス)
  2. JavaScript Object Notation - Wikipedia