もた日記

くだらないことを真面目にやる

Djangoメモ(29) : migrateでモデルに閲覧数カウント用のフィールドを追加

Python 3.6.4 Django 2.0.2

A Complete Beginner's Guide to Djangoのチュートリアルを参考にモデルに閲覧数カウント用のフィールドを追加してみる。


モデルにフィールド追加

migrateコマンドを使ってTopicモデルに閲覧数カウント用のviewsフィールドを追加してみる。
作業を進める前に適用していないマイグレーションがないか確認しておく。No migrations to applyとなればよい。

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  No migrations to apply.

まずboards/models.pyにフィールドの情報を追加する。

class Topic(models.Model):
    subject = models.CharField(max_length=255)
    last_updated = models.DateTimeField(auto_now_add=True)
    board = models.ForeignKey(Board, on_delete=models.CASCADE, related_name='topics')
    starter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='topics')
    views = models.PositiveIntegerField(default=0)   # <- here

    def __str__(self):
        return self.subject

閲覧数は正の整数なのでviewsPositiveIntegerFieldとして追加している。


migrateコマンド実行

モデルにフィールドを追加したのでマイグレーションを実行してデータベースに反映してみる。
最初にmakemigrationsコマンドでマイグレーションファイルを作成する。

$ python manage.py makemigrations
Migrations for 'boards':
  boards/migrations/0002_topic_views.py
    - Add field views to topic

コマンドを実行するとboards/migrations/0002_topic_views.pyというマイグレーションファイルが作成される。
ファイルの中身は以下のようにフィールドを追加する処理が記述されている。

# Generated by Django 2.0.2 on 2018-03-26 14:14

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('boards', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='topic',
            name='views',
            field=models.PositiveIntegerField(default=0),
        ),
    ]

マイグレーションを実行する前に現在の状態をshowmigrationsで確認してみる。
以下のように0002_topic_views[X]となっておらず適用されていないことがわかる。

$ python manage.py showmigrations boards
boards
 [X] 0001_initial
 [ ] 0002_topic_views

migrateコマンドでマイグレーションを実行する。

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  Applying boards.0002_topic_views... OK

実行後はマイグレーションが適用済みになり、データベースのboards_topicテーブルにviewsカラムが追加されている。

$ python manage.py showmigrations boards
boards
 [X] 0001_initial
 [X] 0002_topic_views


ビュー、テンプレートの変更

フィールドは追加できたので閲覧数をカウントできるようにboards/views.pyを編集する。

from django.shortcuts import get_object_or_404, render
from .models import Topic

def topic_posts(request, pk, topic_pk):
    topic = get_object_or_404(Topic, board__pk=pk, pk=topic_pk)
    topic.views += 1
    topic.save()
    return render(request, 'topic_posts.html', {'topic': topic})

topic.views += 1topic.save()でビュー関数が呼ばれる度にカウントアップして保存しているので閲覧数がカウントできる。
次に閲覧数を表示するようにtemplates/topics.htmlを編集。

{% for topic in topics %}
  <tr>
    <td><a href="{% url 'topic_posts' board.pk topic.pk %}">{{ topic.subject }}</a></td>
    <td>{{ topic.starter.username }}</td>
    <td>{{ topic.replies }}</td>
    <td>{{ topic.views }}</td>  <!-- here -->
    <td>{{ topic.last_updated }}</td>
  </tr>
{% endfor %}

試しに何回かアクセスしてみるとViewsの数が増えていくことが確認できる(ただし、これだと同じユーザーで何回もカウントしてしまうので後のチュートリアルで変更するとのこと)。

f:id:wonder-wall:20180326232011p:plain


まとめ

  • データベーススキーマを変更するにはまずmodels.pyを編集
  • makemigrationsでマイグレーションファイルを作成
  • migrateでマイグレーションを実行
  • showmigrationsでマイグレーションの状態を確認
  • ビュー関数でtopic.views += 1のようにして閲覧数をカウント