前段
SNS系アプリにほぼ必須のフォロー機能をDjangoで実装しました。
ライブラリ不使用の自前実装になります。
各自用途や要件に合わせてカスタマイズしてください。
開発環境
- Django
- Python 3.8.5
- MySQL
- Visual Studio Code
※SQLite3でもほぼコード変更なしで書けます。
#フォロー機能の具体的な要件
- フォローすることができる/解除もできる
- 自分自身をフォローすることはできない
- フォロー数、フォロワー数を確認できる
フォロワーの一覧表示などはここでは省きます。
必要最小限の機能要件を実装します。
#テーブル設計
テーブルを1つだけ作成して済ましてしまう方法もありますが、個人的にSQL文が冗長になったり、テーブル管理がしにくい印象を持ったので今回は2つ用意します。
follow_relationテーブル
データ | 格納する情報 | データ型 |
---|---|---|
user_id | フォローする側のユーザーID | UUID |
followed_id | フォローされる側のユーザーID | UUID |
follow_countテーブル
データ | 格納する情報 | データ型 |
---|---|---|
user_id | ユーザーID | UUID |
follow | フォローしている数 | INT |
followed | フォローされている数 | INT |
follow_relation
テーブルは、ユーザー間のフォロー状態の管理、follow_count
テーブルはユーザーのフォロー数、フォロワー数の管理をしています。
#views.pyの編集
テーブルができたらさっそくフォロー機能を実装していきましょう。
フォロー機能のおおまかな流れは以下のようになります。
ページのリクエスト
↓
followd_status関数にてフォロー状態を確認&表示
↓
フォローボタンを押す
↓
follows関数がフォロー状態に応じて処理
↓
元のページにリダイレクト
では以下コードになります。
@login_required
def followed_status(request, accesskey):
# 省略
# 各自必要なパラメータを取得してください
# データベースへの接続
connection = MySQLdb.connect(
host='localhost',
user='***',
passwd='***',
db='***',
charset="utf8"
)
# カーソルの取得
cursor = connection.cursor()
# クエリのセット
follow_relation = "SELECT COUNT(*) FROM follow_relation where user_id = UUID_TO_BIN(%s) and followed_id = UUID_TO_BIN(%s);"
# クエリの実行
# user_id、followed_idは各自で取得
cursor.execute(follow_relation, (user_id, followed_id))
row_follow = cursor.fetchone()
follows = row_follow[0]
# ログインユーザーとページユーザーが同一人物か判定
# 同一人物ならフォローできないようにします
if followed_id == user_id:
followed_status_code = 1
else:
followed_status_code = 2
# もしfollowsが0より大きかったらTrue
# followsが0だったらFalseを返す
followed = False
if follows > 0 :
followed = True
return followed_status_code, followed
必要なパラメータは各自別テーブルから引き出してください。
今回必要なのはフォローする側とされる側のIDのみです。
user_id
がフォローする側、followed_id
がフォローされる側です。
- ユーザー同士のIDを照合します
ステータスコードを付与して同一人物か判別します。
followed_status_code = 1
なら自分自身(フォローできない)
followed_status_code = 2
なら他人同士(フォローできる)
になります。
- フォロー状態を確認します
TrueとFalseでフォロー状態を確認します。
False
ならまだフォローしていない
True
なら既にフォローしている
になります。
では、次にfollows関数を見ていきます。
@login_required
def followes(request, accesskey):
# 省略
# 各自必要なパラメータを取得してください
# データベースへの接続
connection = MySQLdb.connect(
host='localhost',
user='***',
passwd='***',
db='***',
charset="utf8"
)
# カーソルの取得
cursor = connection.cursor()
# 共通クエリをセットしてください
# ここで必要な情報を取得しておきます
# 自分自身はフォローできないようにする
if user_id == followed_id:
followed = False
# セッションにフォロー状態を保存します
request.session['page_followed_status'] = followed
else:
if followed == False:
# フォローするときの処理になります
# クエリのセット
# 新規フォロー関係の挿入
follow_reation = "INSERT INTO follow_relation (user_id, followed_id) values(UUID_TO_BIN(%s), UUID_TO_BIN(%s));"
# フォローする側ユーザーのフォロー数を1つ増やす
follow_update = "UPDATE follow_count SET follow = follow + 1 where user_id=UUID_TO_BIN(%s);"
# フォローされる側ユーザーのフォロワー数を1つ増やす
followed_update = "UPDATE follow_count SET followed = followed + 1 where user_id=UUID_TO_BIN(%s);"
# クエリの実行
cursor.execute(follow_relation, (user_id, followed_id))
cursor.execute(follow_update, (user_id, ))
cursor.execute(followed_update, (followed_id, ))
# 接続を終了する
cursor.close()
connection.commit()
connection.close()
# フォローした状態にする
followed = True
request.session['page_followed_status'] = followed
else:
# フォローを外すときの処理になります
# クエリのセット
# フォロー関係の削除
follow_relation = "DELETE FROM follow_relation where user_id=UUID_TO_BIN(%s) and followed_id = UUID_TO_BIN(%s);"
# フォローを外す側ユーザーのフォロー数を1つ減らす
follow_update = "UPDATE follow_count SET follow = follow - 1 where user_id=UUID_TO_BIN(%s);"
# フォローを外される側ページユーザーのフォロワー数を1つ減らす
followed_update = "UPDATE follow_count SET followed = followed - 1 where user_id=UUID_TO_BIN(%s);"
# クエリの実行
cursor.execute(sql_followrelation_delete, (user_id, followed_id))
cursor.execute(sql_follow_update, (user_id, ))
cursor.execute(sql_followed_update, (followed_id, ))
# 接続を終了する
cursor.close()
connection.commit()
connection.close()
# フォローしていない状態にする
followed = False
request.session['page_followed_status'] = followed
return redirect('元のページ', accesskey)
こちらはif文で分岐させてフォローするorフォロー解除の実際の処理をおこなっています。そして最後にフォローの状態を切り替えています。元のページにリダイレクトして終了です。(今回はAjaxなどを使用しないためページ遷移が生じています)
最後に表示用のviewを編集します。
@login_required
def result(request, accesskey):
# 省略
# フォローの状態を把握する
status = followed_status(request, accesskey)
followed_status_code = status[0]
followed = status[1]
# フォローの状態をセッションに保存(一時的)
request.session['page_followed_status'] = followed
params = {
# 省略
'page_followed_status': followed,
'page_followed_status_code': followed_status_code,
}
return render(request, 'result.html', params)
該当箇所のみ記載しています。
followed_status
関数を呼び出してフォロー状態を確認しています。
(followed_status
関数では、ステータスコードとフォロー状態が返されます。)
そしてセッションに一時的に保存してます。
#urls.pyの編集
urlpatterns = [
# 省略
path('元のページ', views.pages, name='各自で設定'),
path('元のページ/follow/', views.follows, name="follows"),
# 省略
]
テンプレートの編集
最後にテンプレートです。
<!-- フォローボタンを追記 -->
{% if page_followed_status_code is 2 %}
{% if page_followed_status is False %}
<p><a href="{% url 'follows' page_accesskey %}">フォローする</a></p>
{% else %}
<p><a href="{% url 'follows' page_accesskey %}">フォローをやめる</a></p>
{% endif %}
{% endif %}
ステータスコードが2
の場合(自分自身でなく他人同士の場合)のみ表示されるようになっています。
そしてフォロー状態がFalse
のとき「フォローする」、True
のとき「フォローをやめる」と表示させるためif分岐させています。
リンクが押されるとページ移動先でfollows関数が呼び出されフォロー処理をして、また元のページにリダイレクトされるような流れになってます。
#最後に
自分なりにコードを改変して使ってみてください。
「いいね機能」もほぼ同様に実装することができます!