JS memo

お洒落にJavaScript。

2019年2月17日20:12

Djangoとjavascriptでいいね!ボタンを自作

instagramやqiitaのいいねボタンを見て、自作のいいねボタンを作成して見ました。

このサイトはpythonのDjangoで構築しているので、バックエンドをDjango、フロントエンドをjavascriptで実装しています。

前半戦はDjangoを使ってバックエンドでやったことをまとめています。後半戦はjavascriptを使ったフロントエンドでの作業について書きます。

後半戦はこちら
目次
  1. 今回実装した内容
  2. 参考にした動画
  3. Djangoについて
  4. いいねボタンの仕組み
  5. Djangoファイルの操作手順
  6. 余談
  7. まとめ

今回実装した内容

今回作成したいいねボタンをGit Hubに載せています。

Git Hubはこちらから

ほんとはデモページを作れたらよかったのですが、余談でもお話しした通り、実装できないので動画でご紹介します。

インスタグラムのいいねと同じように、クリックしたら1いいねがついて、もう一度タップすると消えます。

またページをリロードしてもいいねの履歴が残るようにしてあります。

1ユーザーにつき1クリックできる使用になっています

参考にした動画

今回は以下の動画を元にして、カスタマイズしていきました。

この動画はすでにdjangoでサイトを構築した後から始まるのでpythonとdjangoの基礎を理解していないと少し難しいかもしれません。

Djangoについて

まずはDjangoについて少しお話いたします。

Djangoとは

pythonで作られたwebフレームワークの一つで、高性能なWebアプリケーションを最速で作成することが可能です。

InstagramもDjangoで作成されています!

ちなみに私はDjango大好きです笑

Djangoの基本構成

-- project/
    -- app/
        -- admin.py ●
        -- app.py
        -- models.py ● 
        -- urls.py ●
        -- views.py ●
        -- templates/
           -- app/
              -- index.html ●
    -- project/
        -- setting.py ●
        -- urls.py
        -- manage.py

シンプルなDjangoの構造です。他にもありますが、今回はこれだけ理解していればいいだろうというファイルのみ記載しています。

まずプロジェクトがあって、その中にプロジェクト上で動かすアプリケーションの設定をするappフォルダとprojectの設定をするフォルダの二種類が含まれています。

※今回使用するファイルに●を記載しています。

上記のファイルの役割をまとめておきます。下記以外にも多くの役割がありますが、今回の場合に限定しています。

app配下

ファイル名役割
admin.pymodels.pyで定義したモデルを登録する
app.pyアプリの名前を登録する
models.pyブログの記事やタイトルなどのデータベース
urls.pyviews.pyで定めれれたどのデータを送るディレクトリを設定する。
views.pymodels.pyのデータをカスタマイズして表示させたいhtmlファイルに送る。
templates表示するhtmlファイルを置く

2階層目のproject配下

ファイル名役割
setting.py日本語で表示などのプロジェクトの設定をする
urls.pyドメイン以下のディレクトリをアプリに振り分ける
manage.pyプロジェクトを動かす際に呼び出すファイル

わかりやすい図つきの解説があったので、共有しておきます。

Djangoを最速でマスターする part1

いいねボタンの仕組み

実際にコードを書く前にいいねボタンの仕組みを簡単に説明しておきます。

  1. いいねをしたユーザーを登録するデータベース(like)を作成
  2. リクエストされるといいねの数とユーザーのいいね状態を記録するページを作成
  3. 作成したページがリクエストされた時に上記の処理を行うclassを定義
  4. htmlファイルにいいねボタンを設置
  5. いいねボタンが押された時に3の処理をリクエストするjsを設定

Djangoファイルの操作手順

※djangoプロジェクトを既に構築した環境からです。

データベースを追加

app/models.pyにユーザー情報(user)といいね情報(like)を格納するデータベースを作成

また

models.py

from django.db import models
from django.urls import reverse
from django.conf import settings

class LikeButtonModel(models.Model):
    # ユーザー情報
    user     = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, on_delete=models.CASCADE)
    title    = models.CharField(max_length=100)
    slug     = models.SlugField()
    body     = models.TextField()
    date     = models.DateTimeField(auto_now_add=True)
    thumb    = models.ImageField(default='default.png', blank=True)
    # いいね情報
    like     = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="likes")

    #いいねを設置するページのURLを取得する設定
    def get_absolute_url(self):
        return reverse("app:like_page", kwargs={"slug": self.slug})

    #いいね情報を記録するページの設定
    def get_api_like_url(self):
        return reverse(""app:like_api", kwargs={"slug": self.slug})

※動画のuserの宣言ではon_deleteが記載されていませんでしが、Djangoのバージョンによっては必須になります。

ページの設定

次にいいねの数とユーザーのいいねの状態を操作するページのURLをurl.pyに設定します。

そして後ほど定義するリクエストされるといいねの数とユーザーのいいね状態を更新するclass(LikeButton)を呼び出すよう設定します。

urls.py

from django.conf.urls import url
from django.contrib import admin
from . import views
from .views import (
  LikeButton,
)
app_name = 'app'

urlpatterns = [
#今回いいねボタンを設置するページ
url(r'^(?P[\w-]+)/$', views.LikePage, name="like_page"),
#いいね情報を格納するページ
url(r'^(?P[\w-]+)/like/$', LikeButton.as_view(), name='like_api'),
]

いいね情報を更新、保持する

views.pyにいいねボタンがクリックされた時にユーザーのいいねの状態といいねの数を更新するよう設定します。

この実装はDjango REST Frameworkを使用しています。下記を参照にしてください。

https://www.django-rest-framework.org/api-guide/views/

settings.py

INSTALLED_APPS = [
    ............
    'rest_framework',
]

views.py

from django.shortcuts import render, get_object_or_404, redirect
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from django.contrib.auth.models import User
from .models import LikeButtonModel

class LikeButton(APIView):
    authentication_classes = (authentication.SessionAuthentication,) #ユーザーが認証されているか確認
    permission_classes = (permissions.IsAuthenticated,)

    def get(self, request, slug=None, format=None):
        obj = get_object_or_404(LikeButtonModel, slug=slug) #いいねボタンを設置しているページの情報取得
        url_ = obj.get_absolute_url() #いいねボタンを設置しているページのURL取得
        status = request.GET.getlist('status') #後半戦で説明
        status = bool(int(status[0])) 
        user = self.request.user #ユーザー情報の取得
        if user in obj.like.all(): #ユーザーがいいねをしていた場合
            if not(status):
                liked = True
            else:
                obj.like.remove(user) #likeからユーザーを外す
                liked = False
        else:              #ユーザーがいいねをしていない場合
            if not(status):
                liked = False
            else:
                obj.like.add(user) #likeにユーザーを加える
                liked = True
        data = {
            "liked": liked,
        }
        return Response(data)

いいねボタンが押された時はユーザーをlikeに登録し、ステータスをいいねした状態に更新します。

逆にいいねを外した時はユーザーをlikeから削除し、ステータスをいいねしていない状態にします。

このリクエストはページが読み込まれた時にユーザーの状態を確認する時といいねが押された時の二種類があります。このリクエストの判別をstatusで行います。このstatusについては後半戦で説明します。

余談

ふとInstagramやfacebookのようないいねボタンをこのサイトに設置したくなったので自作 してみました。

が、このサイトはユーザー登録機能を設置していないので実装が難しいということを作成途中に気が付きました笑

そのため、今回は完成したイイネボタンをお見せできなかったのですが、将来ユーザー登録機能を追加したら実装しようと思います。いつになるか分からないけど笑

まとめ

以上がバックエンドでした作業です。

動画ではいいねの数を更新するページとユーザーのいいね状態を更新するページの二種類を作成していましたが、
今回は一つにまとめて作成しました。

ここまでできれば、あとはjavascriptのajaxを実装するだけなので後半戦はもっと楽なはず!笑

後半戦はこちら

お疲れ様でした!