モデルの定義
これまでに作成したユーザ、アイテム、評価値テーブルと、各推薦リストテーブルに対応したモデルを定義します。モデルクラスは、recsys_django/online/models.pyに記述します。作成した各テーブルのモデルの定義は下記のコマンドで確認できます。
(venv_recsys_django) $ export DB_USER=rsl
(venv_recsys_django) $ export DB_PASSWORD=【パスワード】
(venv_recsys_django) $ python manage.py inspectdb
上記のコマンドを実行した結果、出力される内容を参考にモデルクラスを定義しましょう。online/models.pyに下記のコードを記述してください。
リスト1: recsys_django/online/models.py
from django.db import models
class User(models.Model):
    """ユーザモデル
    Attributes
    ----------
    user_id : IntegerField
        ユーザID
    name : TextField
        ユーザ名
    age : IntegerField
        年齢
    sex : CharField
        性別
    """
    user_id = models.IntegerField(primary_key=True)
    name = models.TextField()
    age = models.IntegerField(blank=True, null=True)
    sex = models.CharField(max_length=1, blank=True, null=True)
    class Meta:
        managed = False
        db_table = 'users'
    def __str__(self):
        return '{}:{}'.format(self.user_id, self.name)
class Item(models.Model):
    """アイテムモデル
    Attributes
    ----------
    item_id : IntegerField
        アイテムID
    name : TextField
        アイテム名
    red : IntegerField
        赤身の特徴量
    white : IntegerField
        白身の特徴量
    shining : IntegerField
        光物の特徴量
    """
    item_id = models.IntegerField(primary_key=True)
    name = models.TextField()
    red = models.IntegerField(blank=True, null=True)
    white = models.IntegerField(blank=True, null=True)
    shining = models.IntegerField(blank=True, null=True)
    class Meta:
        managed = False
        db_table = 'items'
    def __str__(self):
        return '{}:{}'.format(self.item_id, self.name)
class Rating(models.Model):
    """評価値モデル
    Attributes
    ----------
    user : ForeignKey[User]
        対象ユーザ
    item : ForeignKey[Item]
        対象アイテム
    rating : IntegerField
        評価値
    """
    user = models.ForeignKey(User, models.CASCADE)
    item = models.ForeignKey(Item, models.CASCADE)
    rating = models.IntegerField()
    class Meta:
        managed = False
        db_table = 'ratings'
    def __str__(self):
        return '{}:{}:{}'.format(self.user_id, self.item_id, self.rating)
class ReclistPopularity(models.Model):
    """人気ベース推薦リストモデル
    Attributes
    ----------
    rank : FloatField
        推薦順位
    item : ForeignKey[Item]
        推薦アイテム
    score : FloatField
        推薦スコア
    """
    rank = models.FloatField()
    item = models.ForeignKey(Item, models.CASCADE)
    score = models.FloatField()
    class Meta:
        managed = False
        db_table = 'reclist_popularity'
    def __str__(self):
        return '{}:{}:{}'.format(self.rank, self.item, self.score)
class ReclistSimilarity(models.Model):
    """アイテム類似度ベース推薦リストモデル
    Attributes
    ----------
    base_item : ForeignKey[Item]
        ベースアイテム
    rank : FloatField
        推薦順位
    item : ForeignKey[Item]
        推薦アイテム
    score : FloatField
        推薦スコア
    """
    base_item = models.ForeignKey(Item, models.CASCADE, related_name='base_item')
    rank = models.FloatField()
    item = models.ForeignKey(Item, models.CASCADE)
    score = models.FloatField()
    class Meta:
        managed = False
        db_table = 'reclist_similarity'
    def __str__(self):
        return '{}:{}:{}:{}'.format(self.base_item, self.rank, self.item, self.score)
class ReclistItemcf(models.Model):
    """アイテムベース協調フィルタリングに基づく推薦リストモデル
    Attributes
    ----------
    user : ForeignKey[User]
        対象ユーザ
    rank : FloatField
        推薦順位
    item : ForeignKey[Item]
        推薦アイテム
    score : FloatField
        推薦スコア
    """
    user = models.ForeignKey(User, models.CASCADE)
    rank = models.FloatField()
    item = models.ForeignKey(Item, models.CASCADE)
    score = models.FloatField()
    class Meta:
        managed = False
        db_table = 'reclist_itemcf'
    def __str__(self):
        return '{}:{}:{}:{}'.format(self.user, self.rank, self.item, self.score)
online/models.pyではdjango.db.models.Modelクラスを継承した各モデルを定義しています。ユーザモデル、アイテムモデル、評価値モデルは、それぞれUser、Item、Ratingクラスとして定義しています。また、各推薦リストモデルはReclist*クラスとして定義しています。
テーブルのカラムはモデルクラスのクラス属性として定義します。例えば、Userクラスにはnameを定義しています。このクラス属性はFieldクラスのインスタンスとして定義します。TextFieldはテキストフィールドを表します。必要に応じて、blankやnullなどのFieldクラスのフィールドオプションを指定します。なお、ユーザテーブルとアイテムテーブルにおいては、それぞれuser_id、item_idのカラムを主キーとして設定しました。これらに対応して、UserモデルとItemモデルでは、それぞれに対応するフィールドとしてuser_id、item_idのフィールドオプションにprimary_key=Trueを設定しています。一方で、RatingモデルやReclist*モデルにおいては、明示的には主キーに対応するフィールドを定義していません。主キーフィールドの定義を省略すると、自動的にidという名前で主キーフィールドが追加されます。
モデルについては、文献[1][2]を参照してください。
モデルの準備ができましたので、マイグレーションを実行します。まず、下記のコマンドでマイグレーションファイルを作成します。
(venv_recsys_django) $ python manage.py makemigrations online
Migrations for 'online':
  online/migrations/0001_initial.py
    - Create model Item
    - Create model Rating
    - Create model ReclistItemcf
    - Create model ReclistPopularity
    - Create model ReclistSimilarity
    - Create model User
recsys_django/online/migrations/ディレクトリに0001_initial.pyが作成されました。下記のコマンドでマイグレーションが実行する内容を確認してみましょう。
(venv_recsys_django) $ python manage.py sqlmigrate online 0001
BEGIN;
--
-- Create model Item
--
--
-- Create model Rating
--
--
-- Create model ReclistItemcf
--
--
-- Create model ReclistPopularity
--
--
-- Create model ReclistSimilarity
--
--
-- Create model User
--
COMMIT;
このようにSQLが出力されました。ただし、今回はいずれも既にテーブルを作成済みですので、マイグレーションにより新規にテーブルが作成されることはありません。では、マイグレーションを実行してみましょう。
(venv_recsys_django) $ python manage.py migrate
Operations to perform:
  Apply all migrations: accounts, admin, auth, contenttypes, online, sessions
Running migrations:
  Applying online.0001_initial... OK
マイグレーションの詳細は文献[2][3]を参照してください。
参考
- はじめての Django アプリ作成、その2 | Django ドキュメント | Django # モデルの作成
- 現場で使える Django の教科書《基礎編》 # 第6章 モデル (Model)
- 現場で使える Django の教科書《基礎編》 # 第11章 データベースのマイグレーション