Python Django modelAdminカスタマイズ編

Django

DjangoのAdminでデータ管理できるのとても便利ですね。
ただ、このデータの登録や更新のときにちょっと処理を追加したくなるときがあります。
そんなときにどうすればよいかについて説明します。

Django結構何でもできますね。いろいろ用意されています。

処理を追加したいときに基本的な方法

前提
  • 処理を追加したい対象となるテーブルをtable_nameとします。

方法は、簡単です。admin.pyファイルにtable_nameAdminクラスを追加して、そこにやりたいことを書くだけです。
例えば、新規レコードを追加するときに、入力された値を見て、処理を加えたい場合、クラスの中でsave_modelメソッドをオーバーライドして、そこに必要な処理を書くといった感じです。
削除するときには、delete_modelメソッドをオーバライドするとかです。

ちなみにtable_nameAdminクラスの親クラスには、こんなメソッドが定義されています。
親クラスは、admin.modelAdminクラスです。

modelAdminクラスに定義されている主なメソッド
メソッド名役割
ModelAdmin.save_model(requestobjformchange)追加や更新が発生したときに呼び出されて、変更情報をデータベースに反映させる。
ModelAdmin.delete_model(requestobj)削除が発生したときに呼び出されて、変更情報をデータベースに反映させる。
ModelAdmin.get_urls()モデルの管理画面のURLを返します。

もっと見てみたいという方は、公式ドキュメントへどうぞ!

実際にやってみよう

例として、ブックマークを管理するカテゴリークラスとリンククラスを用意します。
※このモデルを選んだ理由は特にないです。(中身もペラペラです)
※皆さんは、ご自身のモデルでお試しくださいませ。

models.pyの中身は以下のような感じです。
ブックマークを表すLinkクラスには、orderが定義されていて、これは、ブックマークの表示順位を表しています。新規にブックマークを登録する際に末尾に付け加えるには問題ないですが、
例えば、先頭に表示したいときには、今ある優先順位を一つずつずらしてあげないといけません。
今回は、その処理を追加してみます。
(それって、設計的にどうなの?という話は今回置いといてください。。。)

from django.db import models↲                                                   
↲                                                                               
# Create your models here.↲                                                     
class Category(models.Model):↲                                                 
    category = models.CharField(max_length=128)↲                               
↲                                                                               
    def __str__(self):↲                                                        
        return '<Category: id={} text={}>'.format(self.id, self.category)↲     
↲                                                                               
↲                                                                               
class Link(models.Model):↲                                                     
    link_to = models.CharField(max_length=1000)↲                               
    link_title = models.CharField(max_length=128)↲                             
    category = models.ForeignKey('Category', on_delete=models.CASCADE)↲         
    order = models.IntegerField()↲                                             
    input_date = models.DateField(auto_now_add = True)↲                        
↲                                                                               
↲                                                                               
    def __str__(self):↲                                                        
        return '<Link: id={} text={} order={}>'.format(self.id, self.link_title, self.order)↲

次に、アプリケーションフォルダ内にあるadmin.pyファイルを開いて、LinkAdminクラスを作成します。このクラスの中で、新規作成、更新、削除したときの表示順位変更処理を書いていきます。

from django.contrib import admin↲                                                                                                  
from django.db.models import F↲                                                                                                    
from .models import *↲                                                                                                             
↲                                                                                                                                  
↲                                                                                                                                  
class LinkAdmin(admin.ModelAdmin):~↲                                                                                               
    def save_model(self, request, obj, form, change):~↲                                                                            
        qset = Link.objects.filter(category__exact=obj.category)\↲                                                                 
                .filter(order__gte=obj.order)↲                                                                                     
        qset.update(order=F('order')+1)↲                                                                                           
        for item in qset:~↲                                                                                                        
            item.save()↲                                                                                                           
↲                                                                                                                                  
        super(LinkAdmin, self).save_model(request, obj, form, change)↲                                                             
↲                                                                                                                                  
↲                                                                                                                                  
    def delete_model(self, request, obj, form, change):~↲                                                                          
        qset = Link.objects.filter(category__exact=obj.category)\↲                                                                 
                .filter(order__gt=obj.order)↲                                                                                      
        qset.update(order=F('order')-1)↲                                                                                           
        for item in qset:~↲                                                                                                        
            item.save()↲                                                                                                           
↲                                                                                                                                  
        super(LinkAdmin, self).save_model(request, obj, form, change)↲                                                             
↲                                                                                                                                  
↲                                                                                                                                  
admin.site.register(Category)↲                                                                                                     
admin.site.register(Link, LinkAdmin)↲                                                                                              

こんな感じでかけますよ!というものですが、簡単に何をしたか書いておきます。(自分が忘れる)

まず、save_modelメソッドですが、こちら、データの新規登録や更新時に呼び出されます。
qset変数に、全Linkレコードの中で今回登録したレコードの表示順位以上のレコードを検索します。取得したレコードに対し、update関数で、表示順位を+1しています。

ポイント

新規登録したLinkデータは、第三引数のobjに渡されています。


忘れてはならないのが、updateしたレコードに対し、saveメソッドを呼んであげること。
忘れるとupdateしたことが無になります。。。

最後に、親クラスのsave_modelメソッドを実行して、新規登録・更新処理を完了させます。

delete_modelも処理の流れは同じです。
こちらは抜け落ちた空白の表示順位を埋めるため、以降のデータの表示順位を1つずつ繰り上げています。

最後に…

処理は、なるべくシンプルにしたいものですが
どうしても追加したいロジックが出てきてしまうものですよね。
そんなときは、こんなこともできますよ!ということで参考になれば幸いです。

コメント

タイトルとURLをコピーしました