1

私はほぼ一日中、formsとについてのドキュメントを読んでいますModelForms。私はなんとか基本的なものを使用することができましたが、モデルフィールドと非モデルフィールドのマッピングに関するドキュメントにヒントが見つからないため、今は本当に問題があります。それが私の言いたいことです:

私はこのモデルを持っています:

class Process(models.Model):
    key         = models.CharField(max_length=32, default="")
    name        = models.CharField(max_length=30)
    path        = models.CharField(max_length=215)
    author      = models.CharField(max_length=100)
    canparse    = models.NullBooleanField(default=False)
    last_exec   = models.DateTimeField(null = True)
    last_stop   = models.DateTimeField(null = True)
    last_change = models.DateTimeField(null = True, auto_now=True)

ユーザーが変更しようとしているフィールドはnameとだけauthorです。pathプロセスの構成ファイルの絶対実パスです。ディレクトリは固定されており、ユーザーはディレクトリがである/home/measure/conf/var/whatever)であるかを気にすることはなく、ファイル名のみを気にします。そのため、にfilenameフィールドが必要ですModelForm

私のフォームは次のようになります:

class ProcessForm(MonitorForm):
    filename = forms.CharField(max_length=250)
    class Meta:
        model  = Process
        fields = ('name', 'filename', 'author')

さて、私が欲しいのは、パス全体ではなく、にfilename保存されているファイル名が含まれていることです。つまり、次のようになります。Process.path

>>> from monitor.forms import ProcessForm
>>> from remusdb.models import Process
>>> 
>>> p = Process(name="test1", path="/tmp/config/a.cnf", author="pablo")
>>> f = ProcessForm(instance=p)
>>> print f["filename"].value()
---> here I want to get "a.cnf"

a.cnf問題は、filename一度呼び出したらフィールドに書き込む方法がわからないことProcessForm(instance=p)です。関数でやろうと思ったのcleanですが、ここがいいところかどうかわかりません。フィールドは多かれ少なかれ読み取り専用であるため、この時点では手遅れになると思います。一度初期化すると、値を変更することはできません。それで、私はそれをどのようにすべきですか?カスタムフィールドを作成してオーバーライドする必要があります__init__か?

私はフォームフィールドのデフォルトのクリーニングを読んでこのアイデアを得て、最初かどうかをテストしたいと思いました。最初にinitをオーバーライドしたくなかったのでto_python、ドキュメントのように最初にメソッドを試してみようと思いました。だから私はクラスを作成しましたRemusFilenameField

class RemusFilenameField(forms.CharField):
    def to_python(self, value):
        print "to_python's value is %s" % value
        return value.upper()

    def clean(self, value):
        print "clean's value is %s" % value
        return value.upper()

filename行をに変更しましProcessForm

filename = RemusFilenameField(max_length=250)

このメソッドがいつどこで呼び出されるかを確認するために、プリントを追加しました。しかし、メソッドはまったく呼び出されません。フォームに制限がないので、私は疑っています。だから私は代わりにこれをしました:

>>> p = {"name": "test1", "filename": "a.cnf", "author": "pablo"}
>>> f = ProcessForm(p)
>>> f.is_valid()
clean's value is a.cnf
True
>>> print f["filename"].value()
a.cnf

to_pythonメソッドも呼び出されておらず、何か違うものが返されるので、私は見ることを期待していましたA.CNFclean

私はこれをどのように解決するのか、そしてこれがまったく良い考えであったかどうかさえわかりません。私の次のprobelmは、f.save()実行されたときに正しいpathものを生成してにfilename保存する必要があるということinstanceです。私はcleanメソッドでそれを行いますか、それともこれのためのより良いオプションがありますか?

編集:私はフォームを作成するための解決策があると思います(使用法で識別するためにソースコード全体を読む必要がありましpython2.6/site-packages/django/forms/models.pymodel_to_dict

from django.forms.models import model_to_dict
import os

class ProcessForm(MonitorForm):
   filename = RemusFilenameField(max_length=250)
   def __init__(self, *args, **kwargs):
       super(ProcessForm, self).__init__(*args, **kwargs)
       try:
           proc = kwargs["instance"]
           filename = os.path.basename(proc.path)
           self.initial.update({'filename': unicode(filename)})
       except:
           pass
   class Meta:
       model  = Process
       fields = ('name', 'filename', 'author')

save()それはうまくいくことを知っています:)今私はメソッドを修正する方法を理解する必要があります

4

2 に答える 2

2

save() メソッドは、フォームに追加の保存ロジックを配置するのに適した場所です。

def save(self, commit=True):
    proc = super(ProcessForm, self).save(commit=False)
    filename = cleaned_data['filename']
    # additional logic to alter filename
    proc.path = filename
    if commit:
        proc.save()
    return proc
于 2012-10-06T07:03:39.327 に答える
1

フォームのフィールドでメソッドを呼び出すという点ではto_python()、コードは正しいですが、cleaned_dataディクショナリから値を取得する必要があります。

>>> p = {"name": "test1", "filename": "a.cnf", "author": "pablo"}
>>> f = ProcessForm(p)
>>> f.is_valid()
clean's value is a.cnf
True
>>> f.cleaned_data['filename']
'A.CNF'

モデルの保存にロジックが必要な場合はsave()、モデルでオーバーライドできます。djangodocsでも説明されています。

drewmanが言ったようsave() に、ModelFormのメソッドをオーバーライドすることも検討する必要がありますsave()。コード内の他の場所からモデルインスタンスのメソッドを呼び出す際のコードには影響しません。

于 2012-10-06T13:12:02.427 に答える