2009-10-12 9 views
11

カスタムフォームでは、モデルのフィールドの一意性(つまり、unique=Trueが設定されている)をどのように検証しますか?ModelFormを使用せずにunique = Trueフィールドを検証/クリーン()する方法は?

私はdjangoのModelFormがBaseModelFormのclean()メソッド内で呼び出されるvalidate_unique()関数を自動的に実行することを知っています.ModelFormを使用すると、これは(管理者の場合と同様に)正しく処理されます。

しかし、私は自分のフォームを一から作成しています。これをどうやって自分で処理できるのでしょうか?私は

...私の最大の障害とは、データがクリーニングされているときに、フォームに添付されているオブジェクトを知っていると思ういくつかのコード:

class UserProfile(CreatedModifiedModel): 
    user   = models.ForeignKey(User, unique=True) 
    display_name = models.CharField('Display Name',max_length=30, 
         blank=True,unique=True) 

class EditUserProfileForm(forms.Form): 
    display_name = forms.CharField(required=False,max_length=30) 

    # "notifications" are created from a different model, not the UserProfile 
    notifications = forms.MultipleChoiceField(
         label="Email Notifications", 
         required=False, 
         widget=forms.CheckboxSelectMultiple,) 

    def clean_display_name(self): 
     # how do I run my own validate_unique() on this form? 
     # how do I know which UserProfile object I am working with? 

    # more code follows, including the __init__ which sets up the notifications 
+1

ModelFormの代わりにカスタムフォームを作成する理由はありますか? – tghw

+0

私は別のアプリからのもので、同じEditUserProfileFormで処理される必要がある "通知"フィールドを表示するようにコードを更新しました。私は複数のモデルソースからModelFormを作ることはできないと思っています... – thornomad

答えて

15

ユニークな検証が完全に権利を取得するのは難しいですので、私は希望とにかくのModelFormを使用することをお勧め:複数のモデルからフォームを作成

class EditUserProfileForm(forms.ModelForm): 
    # "notifications" are created from a different model, not the UserProfile 
    notifications = forms.MultipleChoiceField(
         label="Email Notifications", 
         required=False, 
         widget=forms.CheckboxSelectMultiple,) 

    class Meta: 
     model = UserProfile 
     fields = ('display_name',) 

は容易ではないが、この場合はあなただけのModelFormにnotificationsフィールドを追加することができますし、いつものように.cleaned_dataから引き出し:

私はそれを行うだろうかだが、あなたは自分自身を独特の検証に設定されている場合、あなたはいつものように何かを行うことができます
# view 
if request.method == 'POST': 
    form = EditUserProfileForm(request.POST, instance=user_profile) 
    if form.is_valid(): 
     user_profile = form.save() 
     notifications = form.cleaned_data['notifications'] 
     # Do something with notifications. 

:私はここを参照してください二つの問題があります

def clean_display_name(self): 
    display_name = self.cleaned_data['display_name'] 
    if UserProfile.objects.filter(display_name=display_name).count() > 0: 
     raise ValidationError('This display name is already in use.') 
    return display_name 

を。まず、並行性の問題に直面することができます。ここでは、2人のユーザーが同じ名前を送信し、どちらも一意のチェックを渡しますが、1つはDBエラーを取得します。もう1つの問題は、検索から除外するIDがないため、ユーザープロファイルを編集できないことです。

def __init__(self, *args, **kwargs): 
    ... 
    if 'instance' in kwargs: 
     self.id = kwargs['instance'].id 
    ... 

def clean_display_name(self): 
    display_name = self.cleaned_data['display_name'] 
    qs = UserProfile.objects.filter(display_name=display_name) 
    if self.id: 
     qs = qs.exclude(pk=self.id) 
    if qs.count() > 0: 
     raise ValidationError('This display name is already in use.') 
    return display_name 

しかし、その時点であなただけのModelFormsにロジックを複製している:あなたは、あなたの__init__に保管して、クリーニングにそれを使用する必要があると思います。

+1

ちょっと - ありがとう。私は、モデルに対応していないModelFormにフィールドを追加することについて確かではありませんでしたが、私はこれを最初に試してみましょう。私に問題がある場合は、報告する。 – thornomad

+0

tghwありがとう、偉大な答え – PyDroid

関連する問題