【Django】既存レコードを更新するフォームの実装|ModelForm に instance を渡すパターン

スポンサードリンク



Django · ModelForm · 既存レコードの更新

新フォーム(既に登録済のレコードを編集する画面)を Django で実装するのは、新規登録より少しだけ手数が多いです。ModelForm に instance を渡してインスタンス紐付け をする手順を一度押さえれば、ファイル一覧情報の編集・ユーザープロファイル編集・在庫情報の更新など、業務系アプリで頻出する更新画面を量産できます。本記事ではファイル情報の更新を題材に、更新フォーム実装の決まり手を解説します。

この記事では、Djangoでファイル一覧情報を更新する方法について紹介します。

user@sinyblog:~/article 01_section_1.md想定ケース

メディアファイル設定を使って画面からファイルをサーバにアップロードした後、アップロードされたファイルをリスト形式で一覧表示するといった場合(下図)、普通にフォームの定義をしただけでは設定しただけでは情報が更新されません。

更新するには開発サーバの再立ち上げをしないとダメ…なんて状況に陥ることがよくありました。

これでは実用的ではないため、画面を再表示するタイミングで自動的にファイルリストが最新化されるようにします。

 

user@sinyblog:~/article 02_section_2.mdモデルを利用した場合の手順

まず、モデルは以下のようにFileFieldを使ったフィールドを1つ用意しておきます。

python


from django.db import models





class UploadFile(models.Model):

    

    class Meta:

        verbose_name = 'データのアップロード'

        verbose_name_plural = 'データのアップロード'



    file = models.FileField(verbose_name="file Upload", upload_to='csv/')



    def __str__(self):

        """ファイルのURLを返す"""

        return self.file.url

 

メディアの設定は以下とします。

python


MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

MEDIA_URL = '/media/'

 

続いてforms.pyの定義です。

python


from django import forms

from .models import UploadFile

from django.conf import settings





class UploadFileForm(forms.Form):

    

    fname = forms.ChoiceField(label='データファイルの選択',

              choices=lambda:[(os.path.join(os.path.join(settings.MEDIA_ROOT, "csv"), fname.file.name.split("/")[1]), \

                  fname.file.name.split("/")[1]) for fname in UploadFile.objects.all()], required=False))

 

ポイントは以下の部分です。

python


choices=lambda:[(os.path.join(os.path.join(settings.MEDIA_ROOT, "csv"), fname.file.name.split("/")[1]), \ fname.file.name.split("/")[1]) for fname in UploadFile.objects.all()], required=False))

 

ChoiceFieldフィールドオプションのchoicesでlamba関数を使いUploadFileテーブルクラスから全レコードを取得し、ファイルパス情報を取得して(ファイルの絶対パス、ファイル名)の形式でタプルのデータを生成します。

UploadFileテーブルのfile列にはcsv/<ファイル名.csv>のような情報が格納されているので、fname.file.name.split("/")[1]とすることで<ファイル名.csv>の部分だけを抽出しています。

os.path.join(os.path.join(settings.MEDIA_ROOT, "csv"))はcsvが格納されている絶対パスを取得しています。

以上で、画面からファイルアップロードしたあと画面を更新するとファイル一覧が最新状態に更新されるようになります。

 

user@sinyblog:~/article 03_section_3.mdモデルを利用しない場合の手順

先ほどの例ではmodels.pyでFileFieldを使っていたので、ファイルアップロードをするとテーブルにファイルの情報が登録されるため、テーブルレコードの情報を利用することでファイル一覧情報を最新に更新しました。

では、モデルに定義がないケースではどうするか?

たとえば、モデルとしては情報を持っていないが、サーバ上に配置されているファイルの一覧情報をリスト形式で一覧表示したいケースです。

この場合、forms.pyでフォームの定義をしますが、モデルの定義がないため先ほどの方法は使えません。

例えば以下のようにmedia/dataフォルダ配下に存在するファイル一覧をリスト形式で一覧表示するという事例で説明します。

python


from django.core.files.storage import default_storage

from django.conf import settings

import os





def file_list():

    data_path = os.path.join(settings.MEDIA_ROOT, "data")

    _, file_list = default_storage.listdir(os.path.join(settings.MEDIA_ROOT, "data"))

    FILE_LIST = [(os.path.join(data_path, file_name), file_name) for file_name in file_list]

    return FILE_LIST





class FileForm(forms.Form):

    fname = forms.ChoiceField(label='ファイルの選択', choices=file_list())



 

上記の通り、ChoiceFieldを使ってchoicesフィールドに該当のディレクトリに存在しているファイル一覧の情報を渡してあげればリスト形式で画面表示されるフォームが出来上がります。

file_list()はmedia/data配下のファイル一覧を取得して(ファイルの絶対パス,ファイル名)というタプルを生成する関数です。

しかし、この状態だとmedia/data配下にファイルが追加、削除された後に画面を更新してもリスト情報が更新されません。

更新するには開発サーバを再立ち上げなどしないと更新されず、これでは実用的ではありません。

画面更新時にリスト情報を最新状態に更新するには、以下の通り__init__メソッド内でchoicesフィールドを更新する処理を書くだけで実現できます。

python


from django.core.files.storage import default_storage

from django.conf import settings

import os





def file_list():

    data_path = os.path.join(settings.MEDIA_ROOT, "data")

    _, file_list = default_storage.listdir(os.path.join(settings.MEDIA_ROOT, "data"))

    FILE_LIST = [(os.path.join(data_path, file_name), file_name) for file_name in file_list]

    return FILE_LIST





class FileForm(forms.Form):

    fname = forms.ChoiceField(label='ファイルの選択', choices=file_list())



  #ここから追加

    def __init__(self, param):

        forms.Form.__init__(self, param)

        self.fields['model_fname'].choices = get_model_list()

 

以上、Djangoでファイル一覧情報を更新する方法でした。

 

おすすめの記事