【Django REST Framework】ユーザーに紐づいたデータを登録する

Django REST Frameworkおよびajax通信を使用して、フォームに入力した内容を、ログインしているユーザー情報と共にデータベースに登録する方法をご紹介したいと思います。

目次

動作環境

下記の内容で動作を確認しております。

  • python : 3.9.10
  • Django : 4.2.5
  • djangorestframework : 3.14.0

まえがき

実際に機能をご紹介していきますが、Djangoのプロジェクトやアプリの作成方法などは割愛させていただきます。

Djangoを使用した最小限のアプリ作成までの方法などはこちらの記事をご覧いただけたらと思います。

またユースケースとして、フォームを使用してユーザーの好きな食べ物を登録できるページを考えていきます。

また、ログインしているユーザーと紐付けを行いますので、ユーザーによって情報の抽出を行うことができます。

実装

必要なライブラリのインストール

Django REST Frameworkを使用しますので、下記のコマンドを実行して必要なライブラリをインストールします。

pip install djangorestframework==3.14.0

さらに、このライブラリの機能を使用できるようにするため、settings.pyに追記します。

INSTALLED_APPS = [
    ...

    'rest_framework', 
]

カスタムユーザーモデル

本記事では、django-allauthおよびカスタムユーザーモデルを定義して、認証機能を実装していると想定します。

django-allauthを使用した認証機能の実装方法は、こちらの記事をご覧いただけたらと思います。

こちらでは、プロジェクト内に「accounts」というアプリを追加し、さらに下記のようなカスタムユーザーモデルを定義しています。

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    """ カスタムユーザーモデル """

    class Meta:
        verbose_name_plural = 'CustomUser'

models.py

models.pyには、登録する予定の料理に関するクラスを定義します。

from django.db import models

from accounts.models import CustomUser


class Food(models.Model):
    user = models.ForeignKey(CustomUser, verbose_name='ユーザー', on_delete=models.PROTECT)
    name = models.CharField(verbose_name='料理名', max_length=255, primary_key=True)
    created_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)

    class Meta:
        verbose_name_plural = 'Food'

        def __str__(self):
            return self.name

ユーザーを外部キーとしています。

主キーが料理名というクソ仕様ですが、サンプルのためご了承ください。

忘れずにマイグレーションを行います。

python manage.py makemigrations
python manage.py migrate

シリアライザ

次にDRF(Django REST Framework)を使用するのに必要なシリアライザを定義していきます。

シリアライザを使用し、フォーム送信された値のバリデーションを行うことができます。

今回は必要最低限な項目のみで構成しております。

from rest_framework import serializers

from .models import Food
from accounts.models import CustomUser


class FoodSerializer(serializers.ModelSerializer):
    created_at = serializers.DateTimeField(format='%Y-%m-%d', read_only=True)

    class Meta:
        model = Food
        fields = ('name', 'created_at')

        extra_kwargs = {'user': {'write_only': True}}

ビュー

ビューを作成します。

from rest_framework import generics

from .models import Food
from .serializer import FoodSerializer


class FoodCreateView(generics.CreateAPIView):
    queryset = Food.objects.all()
    serializer_class = FoodSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

generics.CreateAPIViewを継承し、およびここまでで作成したモデルシリアライザを使用し上記のように記述するだけで、Foodモデルにレコードを追加するビューが作成できます。

またperform_create()メソッドをオーバーライドし、フォーム送信時に一緒にユーザー情報を付与するようにしています。

ルーティング

最後にルーティング設定を行います。

from django.urls import path
from . import views

app_name = 'app_name'
urlpatterns = [
    ..., 
    path('api/create-food/', views.FoodCreateView.as_view(), name="create_food"), 
]

ここまで設定を行ったところで、実際に機能するのか確認してみます。

開発環境にて、http://127.0.0.1:8000/api/create-food/ にアクセスしてみます。

このように、Foodテーブルに項目を追加できるページが表示されるはずです。

お好きな料理名を入力し「POST」ボタンを押下することで、実際にレコードを挿入することができます。

次からは、この機能を実際のアプリケーション内に組み込んでいきます。

テンプレート

作成したFoodモデルには、下記の3つの項目がありました。

  • user
  • name
  • created_at

「user」はviews.pyで、「created_at」は作成時に自動で補填されますので、ユーザーが入力する必要があるのは「name」のみであることが分かります。

したがって、任意のテンプレート内に、下記のようなフォームを作成しましょう。

<form method="post" action="" id="form__create-food">
    {% csrf_token %}

    <input type="text" name="name" id="name">
    <button id="btn__create-food" type="button">追加</button>
</form>

また同一のテンプレート内に、下記のようなjsスクリプトを追加します。

<script>
    const submitBtn = document.getElementById('btn__create-food');

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = cookies[i].trim();
                // クッキー名からCSRFトークンを探す
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    submitBtn.addEventListener('click', () => {
        let name = document.getElementById('name').value;
        let createEndPoint = "/api/create-food/";

        formData = {
            'name': name
        }
        
        fetch(createEndPoint, {
            method: 'POST', 
            headers: {
                'X-CSRFToken': getCookie('csrftoken'), 
                'Content-Type': 'application/json', 
            },
            body: JSON.stringify(formData)
        })
        .then(res => {
            if (res.ok) {
                console.log('Successfully add food.');
            } else {
                console.error('Error occured during sending data.');
            }
        })
        .catch(error => {
            console.error('Network error:', error);
        });
    });
</script>

テンプレート内に設置したボタンにオンクリックイベントとして、フォーム内容をAjax通信でPOSTするメソッドを定義しています。

このようにすることで、ページ遷移を行うことなくデータベースへレコードを挿入することができます。

もしよりよい方法や、ご指摘などございましたら、ぜひご教示いただけると幸いです。

案件、ありますか?

「メインの仕事があるけれど、週1、2日だけできる仕事ないかな、、、」

「ある程度スキルが身に付いてはきたけど、そのスキルを活用できる場が欲しい」

なんて悩みが以前はありました。

自分で仕事を探しに行くのも大事ですが、蛇の道は蛇。その道の人に頼むことで、自分だけでは見つからないような案件に携わることができます。

IT PRO パートナーズでは、簡単に無料でアカウントを登録でき、さらにはエージェントさんに希望の働き方・案件の種類を提示することでお仕事を紹介してくれます!

登録自体も非常に簡単で、「エージェントさんとの面談を希望する」という欄にチェックをするだけで、エージェントさんから直接連絡をいただくことができます。

驚くほど簡単で正直拍子抜けしてしまいました笑

もしお仕事探しに困っておりましたら、一度登録し案件を眺めてみることをおすすめします!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

勤めていた設計会社を退社し、フリーランスとして活動しています
また、趣味で主にpyhonを用いて機械学習を行なっています!
現在競艇の予測モデルの開発中です。

コメント

コメントする

目次