View on GitHub

評価値の登録と取得

Home

評価値の登録と取得

モデル

backend/api/online/models.py

......
class Rating(models.Model):
    """評価値モデル

    Attributes
    ----------
    id : TextField
        評価値ID
    user : ForeignKey[User]
        対象ユーザ
    movie : ForeignKey[Movie]
        対象映画
    rating : IntegerField
        評価値
    rated_at : DateTimeField
        評価日時
    """
    id = models.TextField(primary_key=True, max_length=43)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    movie = models.ForeignKey(Movie, related_name='movie_ratings', on_delete=models.CASCADE)
    rating = models.FloatField(blank=False, null=False)
    rated_at = models.DateTimeField(blank=False, null=False, auto_now=True)

    class Meta:
        managed = True
        db_table = 'ratings'

    def __str__(self):
        return '{}:{}:{}'.format(self.user.id, self.movie.id, self.rating)

マイグレーション

(recsys_full) backend$ python manage.py makemigrations online --settings config.settings.development
Migrations for 'online':
  api/online/migrations/0003_rating.py
    + Create model Rating
(recsys_full) backend$ python manage.py migrate --settings config.settings.development

テーブルの確認

recsys_full=# \dt
                  List of relations
 Schema |            Name            | Type  | Owner 
--------+----------------------------+-------+-------
...(略)...
 public | ratings                    | table | rsl
 public | users                      | table | rsl
(15 rows)

recsys_full=# \d ratings
                        Table "public.ratings"
  Column  |           Type           | Collation | Nullable | Default 
----------+--------------------------+-----------+----------+---------
 id       | text                     |           | not null | 
 rating   | double precision         |           | not null | 
 rated_at | timestamp with time zone |           | not null | 
 movie_id | integer                  |           | not null | 
 user_id  | uuid                     |           | not null | 
Indexes:
    "ratings_pkey" PRIMARY KEY, btree (id)
    "ratings_id_b3cd9389_like" btree (id text_pattern_ops)
    "ratings_movie_id_c828f845" btree (movie_id)
    "ratings_user_id_dbf12542" btree (user_id)
Foreign-key constraints:
    "ratings_movie_id_c828f845_fk_movies_id" FOREIGN KEY (movie_id) REFERENCES movies(id) DEFERRABLE INITIALLY DEFERRED
    "ratings_user_id_dbf12542_fk_users_id" FOREIGN KEY (user_id) REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED

マッパー

backend/api/online/mappers.py

......
class RatingMapper:
    def __init__(self, obj):
        self.obj = obj

    def as_dict(self):
        rating = self.obj
        
        return {
            'id': rating.id,
            'user_id': rating.user_id,
            'movie_id': rating.movie_id,
            'rating': rating.rating,
            'rated_at': rating.rated_at,
        }

ビュー

backend/api/online/views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import User, Movie, Rating                     # <- Ratingを追加
from .mappers import UserMapper, MovieMapper, RatingMapper  # <- RatingMapperを追加
from .utils import hash
import uuid
......
# ↓追加
class RatingsView(APIView):
    """評価値ビュークラス
    """
    def get(self, request, format=None):
        """評価値を取得する。

        Requests
        --------
        id : str
            評価値ID

        Response
        --------
        ratings : json
            評価値リスト
        """
        # リクエストパラメタの取得
        id = request.GET.get('id')

        # オブジェクトの取得
        ratings = Rating.objects.filter(id=id)

        # レスポンス
        ratings_dict = [RatingMapper(rating).as_dict() for rating in ratings]
        data = {
            'ratings': ratings_dict,
        }
        return Response(data, status.HTTP_200_OK)
    
    def post(self, request, format=None):
        """評価値を登録する。

        Requests
        --------
        id : str
            評価値ID
        user_id : str
            ユーザID
        movie_id : int
            映画ID
        rating : float
            評価値

        Response
        --------
        rating : json
            評価値
        """
        # リクエストパラメタの取得
        id = request.data['id']
        user_id = request.data['user_id']
        movie_id = request.data['movie_id']
        rating = request.data['rating']

        # オブジェクトの登録
        user = User.objects.get(pk=user_id)
        movie = Movie.objects.get(pk=movie_id)
        rating_model = Rating(id=id, user=user, movie=movie, rating=rating)
        rating_model.save()

        # レスポンス
        rating_dict = RatingMapper(rating_model).as_dict()
        data = {
            'rating': rating_dict,
        }
        return Response(data, status.HTTP_201_CREATED)
# ↑追加

URLマッピング

backend/api/online/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('users/', views.UsersView.as_view()),
    path('movies/', views.MoviesView.as_view()),
    path('movies/<int:id>/', views.MovieView.as_view()),
    path('ratings/', views.RatingsView.as_view()),  # <- 追加
]

ブラウザで下記URLにアクセスしてください。

ユーザAPIの実装で登録された【ユーザID】を使って、Contentフォームに、例えば下記のデータを入力し、POSTボタンをクリックしてください。

{
  "id": "【ユーザID】_000001",
  "user_id": "【ユーザID】",
  "movie_id": 1,
  "rating": 3.5
}

ratingsテーブルに下記のように評価値が登録されました。

recsys_full=# SELECT * FROM ratings;
        id         | rating |           rated_at            | movie_id |   user_id   
-------------------+--------+-------------------------------+----------+-------------
 【ユーザID】_000001 |    3.5 | 2025-03-22 15:25:25.670634+09 |        1 | 【ユーザID】 
(1 row)

ブラウザで下記URLにアクセスしてください。

下記のように、登録した評価値のデータが取得できます。

{
    "ratings": [
        {
            "id": "【ユーザID】_000001",
            "user_id": "【ユーザID】",
            "movie_id": 1,
            "rating": 3.5,
            "rated_at": "2025-03-22T06:25:25.670634Z"
        }
    ]
}

同じ映画に対して、再度、評価値を変えて登録してみると、ratingsテーブルの内容が更新されます。

データの登録

一旦、usersテーブルとratingsテーブルの内容を削除したうえで、既存ユーザおよび評価値データを登録しておきます。

recsys_full=# DELETE FROM ratings;
recsys_full=# DELETE FROM users;
offline/data$
 psql recsys_full -U postgres -c "\copy users (id, email_encrypted, email_hash) from 'users.csv' with delimiter E'\t' csv header encoding 'UTF8'"
 psql recsys_full -U postgres -c "\copy ratings (id, user_id, movie_id, rating, rated_at) from 'ratings.csv' with delimiter E'\t' csv header encoding 'UTF8'"

データの確認

recsys_full=# SELECT * FROM users;
recsys_full=# SELECT * FROM ratings;