Django: ModelFormクラスの設定あれこれ

2010年3月21日

しかし、そのフォームクラスに格納された値をモデル(データベース)に格納する際に値を変更したり フォームでは指定しない項目をモデルクラスに持っていて、システム側が値を自動的に格納したりなど 必ずしもフォームの値とモデルで格納したい値とは対応しないと思います。

例えば、以下のような場合です。 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.db import models
from django import forms

class FileUpload(models.Model):
    fname = models.FileField(upload_to="path/to")
    savetime = models.DateTimeField(auto_now_add=True)
    numOfLines = models.IntegerField(blank=True, null=True)  # ファイルの行数

class FileUpload_Form(forms.ModelForm):
    class Meta:
        model = FileUpload  # FileUploadモデルクラスを継承

上記例では、ファイルアップロードアプリケーションを想定しています。

ファイル名: fnameやレコード保存時刻: savetimeはユーザのフォームに対する操作で決定しますが、 ファイルの行数: numOfLinesについてはファイルがアップロードされたあとじゃないと分かりません。
しかし一方で、モデルから派生したフォームクラスは以下のようにデータをモデルクラスに渡して 保存しますよね。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def hoge_handler(req):
    if ( req.method == "POST" ):
        form = FileUpload_Form(req.POST, req.FILES)
        if ( form.is_valid() ):  # 束縛フォームがTrue 
            fc = req.FILES['fname']
            filename = fc.name
            fpath = "/hoge/hoge/file/stored/path/"
            wfp = file(fpath, "wb")
            for chunk in fc.chunks():
                wfp.write(chunk)
            wfp.close()
            ifp.file(fpath, "rb") 
            linecnt = 0
            for line in ifp.readlines():
                linecnt += 1
            form.cleaned_data['numOfLines'] = linecnt  # ファイル行数を格 納
            form.save()

フォームに正しく値が格納されている場合はバリデーターがis_valied()にてTrueを返します。 その場合、formオブジェクトにはcleaned_dataというメンバが付与されています。 これは辞書型のメンバでキーにカラム名(ここではnumOfLines)を指定することでその値にアクセスできます。 そこで値を上記のように書き換えsave()メソッドをコールすれば、値が無事変更された状態でデータベースに格納 されます。


これはきれいなやり方ではなく、少々無理矢理感が否めませんが、 こういったやり方もあるということで参考にされてください。
別の方法として、form.save(commit=False)とすることでモデルインスタンスが得られる とのことですので、当該モデルインスタンスから各カラムを書き換えるというやり方があります。