DjangoでTwitterのようなフォロー、フォロワーの機能を実装する(models.py、ManyToManyField)

2021年12月9日Djangoの豆知識db設計

Djangoでフォロー機能をかんたんに実装したい

Toitterというアプリ名で、Twitterのようなフォロー機能の実現をしてみましょう。

今回はDjangoでなるべく簡単にフォロー機能を実装してみます。models.pyのデータベース定義部分がメインとなります。

またフォロー機能の設計にフォーカスを当てるためユーザーモデルはデフォルトのものを継承するのではなく、あらたにToitterUserモデルを作成していきます。

まずは結論

toitter/models.pyで以下のように定義

class ToitterUser(models.Model):
    username = models.CharField(max_length=30)
    following = models.ManyToManyField("self",related_name="followed_by",symmetrical=False,blank=True)

    def __str__(self):
        return self.name

symmetrical=Falseが重要だった、、。

それでははじめましょう🍻

前提

Git, Docker, 軽くDjango

バージョン

Django==3.2

サンプルコード

Githubのtwitter-like-modelブランチにあります。

ステップ1:環境構築をする

まずはターミナルで、以下のコマンドを順に実行してください。

git clone -b twitter-like-model https://github.com/yeconnect/django-baby-starter-template.git

cd django-baby-starter-template

docker compose up -d

docker compose run --rm web python manage.py migrate

ステップ2:models.pyに記述する

models.pyは以下のようになります。ToitterUserというモデルを定義しました。

from django.db import models

class ToitterUser(models.Model):
    username = models.CharField(max_length=30, primary_key=True)
    # ↓ここ!
    following = models.ManyToManyField("self",related_name="followed_by",symmetrical=False,blank=True)

    def __str__(self):
        return self.username

usernameはすぐに理解できると思いますので、ここからfollowing=models.ManyToManyField(“self", related……….)の一行を解説していきます。

ManyToManyFieldを使う理由

例えば、ユーザーAには複数のフォロワーがおり、そのフォロワーは複数のユーザーをフォローしています。つまり多対多の関係にあります。

よって今回はManyToManyFieldを使います。

“self"とは?

Djangoはmodes.pyで自己参照するとき対象とするモデルに"self"と記述します。今回もToitterUserとToitterUserの関係性となり自己参照モデルです。

AがBをフォローしている時、

AにとってBは「フォローしている人」、BにとってAは「フォロワー」です。後述しますが、このrelated_nameを書くことで、

Aの「フォローしている人」 → A.following.all()

Aの「フォロワー」 → A.followed_by.all()

と簡単に取ってくることができます。

symmetrical=Falseとは?

ManyToManyFieldで自己参照するとき、対象性がある場合とない場合があります。

対象性がある場合としては、友達関係があげられます。

例えばAがBの友達である場合、BもAの友達であることが確定します。(現実世界ではそうでもないかもしれませんが、。)

対象性がない場合としては、今回のようなフォロー、フォロワー関係です。

例えば一般人Aが有名人Bをフォローしているからといって、有名人Bは一般人Aをフォローしているわけではありません。

この対象性のある無しの設定はsymmetrical = True/Falseです。

よって今回のように自己参照のManyToManyFieldで、対象性がない場合はsymmetrical=Falseが必要です。

ステップ3:views.pyでの扱い方

ToitterUserをAとすると、フォローしている人を取得したい場合は

all = A.following.all()

フォロワーを取得したい場合は

all = A.followed_by.all()

と簡単に書けます。

またAがBをフォローするときは

A.following.add(B) # BはユーザBのオブジェクト

AがBをアンフォローするときは

A.following.remove(B) 

ステップ4:動作確認

ブラウザで http://localhost:4989/toitter/ にアクセスしてみましょう!

Toitter

まとめ&おまけ

Django BabyではDjangoの超入門チュートリアルやtipsをアップしていきます!