Django 作成者 作成日時 更新者 更新日時を管理する

## 環境
Windows 11 Home
Python 3.10.2
Django 4.0.2
venv利用あり
(PyPI)
記事の中でインストールあり
条件：関連記事 第1回が完了していること

## 関連記事
Django 第1回：[Django Custom User Model の作成](https://qiita.com/startours777/items/706d38e712b0c737a16a)
Django 第2回：[Django 初回ログイン時にパスワード変更を強制する](https://qiita.com/startours777/items/28db625a9bb81a36d4ad)
Django 第3回：[Django 一定期間パスワードを変更していないユーザにパスワード変更を強制する](https://qiita.com/startours777/items/d550ca9b67cea4408a44)
Django 第4回：[Django ランダムかつ有効期限のあるURLを生成し、上位者に承認してもらいアカウントを発行する](https://qiita.com/startours777/items/529e74062e7054e79517)
Django 第5回：[Django パスワード試行回数ロックとランダムかつ有効期限付きURLでの本人確認による解除](https://qiita.com/startours777/items/5b1fc415e047a2044129)

## 背景
管理画面にデータの作成者、更新者といった情報を追加し簡素な履歴管理を利用したかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/46968e4d-8678-fc34-65b6-baa82e1a59c7.png)

## ulid-py のインストール
データを管理するのにIDでの管理をしようと思い、また連番でもよいのだが、ソート可能なUUID互換のulidを今回は利用した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/2352e063-f596-0b1f-dfb3-2f165db58b31.png)

pipコマンドでインストールする
`pip install ulid-py`

## django-currentuser のインストール

作成者、更新者が登録される際、それはログイン中のユーザとなる。
ユーザを取得するため以下をインストールする。
`pip install django-currentuser`

`settings.py`にミドルウェアを登録する
```python:mysite\settings.py
MIDDLEWARE = (
    ...,
    'django_currentuser.middleware.ThreadLocalUserMiddleware',
)
```

## appの作成
Django appを作成する。pollsの部分はアプリケーション名で、何でもよい
今回はpollsとしたので変更された方は全体的に読み替えていただきたい
`python manage.py startapp polls`

`settings.py`に作成したpollsを登録する
```python:mysite\settings.py
INSTALLED_APPS = [
    ...,
    'polls',
]
```

## appにModelを追加
```python:polls\admin.py
from django_currentuser.db.models import CurrentUserField
from django.db import models
import ulid

class Polls(models.Model):
    id = models.CharField(primary_key=True, default=ulid.new, max_length=26, editable=False)
    name = models.CharField(verbose_name="名前", max_length=50)

    created_by = CurrentUserField(verbose_name="作成者", editable=False, related_name="create_polls")
    create_date = models.DateTimeField(verbose_name="作成日時", auto_now_add=True)
    updated_by = CurrentUserField(verbose_name="更新者", editable=False, related_name="update_polls", on_update=True, )
    update_date = models.DateTimeField(verbose_name="更新日時", auto_now=True)
```

`create_date`は`auto_now_add`であるのに対し、`update_date`は`auto_now`であることに注意。


## appを管理画面に追加
```python:polls\admin.py
from django.contrib import admin
from .models import Polls
class PollsAdmin(Polls):
    class Meta:
        verbose_name = ("Polls")
        verbose_name_plural = ("Polls")


@admin.register(PollsAdmin)
class PollsGroupAdmin(admin.ModelAdmin):
    ordering = ["id",]
    list_display = ["id", "name", "created_by", "create_date", "updated_by", "update_date"]
    search_fields = ["id", "name"]
    readonly_fields = ["id", "created_by", "create_date", "updated_by", "update_date"]
    fieldsets = (
        ("基本情報", {
            "fields":("id", "name", ),
        }),
        ("更新履歴", {
            "fields":("created_by", "create_date", "updated_by", "update_date", ),
        }),        
    )
```
詳細画面、すなわち`fieldsets`で表示させるには
`created_by`, `create_date`, `updated_by`, `update_date`が変更不可のため、`readonly_fields`に記載しておく必要がある
最終的に詳細画面はこのようになる（まだこの時点では表示できない）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/3912359d-d213-7fca-f8c1-7a9fb13b5f9f.png)


## appのマイグレーション
`python manage.py makemigrations`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/c258595c-2ab7-540b-e923-2ac8bbb1798c.png)

`python manage.py migrate`
`python manage.py runserver`

## 動作確認
管理画面にログインするとpollsが追加されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/20798d67-812e-55c1-30b1-2d05e30400e4.png)

「POLLSを追加」から適当にデータを追加してみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/88d2ca50-8458-90f8-75c3-912a33e5c444.png)

この段階では作成者＝更新者である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/abef7d86-1c08-fc9c-81b5-0b8023e87ee0.png)

次に別のユーザでログインし直し、該当のデータを更新してみる
無事、更新者および更新日時が更新された（作成者、作成日時は更新されない）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/1edadcdc-54de-8c96-a235-51fa4854843f.png)

## 注意
`created_by`, `updated_by` ともに `admin.py`の`search_fields`には対応していないようである