3

私は次のものを持っています:

class AccountAdmin(models.Model):

    account = models.ForeignKey(Account)
    is_master = models.BooleanField()
    name = models.CharField(max_length=255)
    email = models.EmailField()

    class Meta:
        unique_together = (('Account', 'is_master'), ('Account', 'username'),)

次に、同じアカウントの別のユーザー名と同じユーザー名で新しい AccountAdmin を作成すると、テンプレートに表示するエラーが表示される代わりに、IntegrityError で壊れてページが停止します。私の見解では、私はただ行くことができればいいのにと思います:

if new_accountadmin_form.is_valid():
    new_accountadmin_form.save()

どうすればこの問題を克服できますか。is_valid()部品の違反についてDBをチェックする2番目のタイプの方法はありunique_together = (('Account', 'is_master'), ('Account', 'username'),)ますか?

ビューで IntegrityError をキャッチする必要はありません。これは、ドメイン ロジックとプレゼンテーション ロジックを組み合わせたものです。同じフォームを 2 ページに表示すると、同じブロックを繰り返さなければならないため、DRY に違反します。また、DRY にも違反しています。同じものに対して 2 つの形式がある場合は、同じ except: をもう一度書かなければならないからです。

4

3 に答える 3

8

次の 2 つのオプションがあります。

a) モデルを保存し、IntegrityError をキャプチャして処理する try ブロックを用意します。何かのようなもの:

try:
    new_accountadmin_form.save()
except IntegrityError:
    new_accountadmin_form._errors["account"] = ["some message"]
    new_accountadmin_form._errors["is_master"] = ["some message"]

    del new_accountadmin_form.cleaned_data["account"]
    del new_accountadmin_form.cleaned_data["is_master"]

b) フォームの clean() メソッドで、a 行が存在するかどうかを確認 forms.ValidationErrorし、適切なメッセージで a を発生させます。例はこちら


だから、b)それは...だから私はドキュメントを参照しました。必要なものはすべてそこにあります。

しかし、それは次のようなものになります:

class YouForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
       """ This is the form's clean method, not a particular field's clean method """
       cleaned_data = self.cleaned_data

       account = cleaned_data.get("account")
       is_master = cleaned_data.get("is_master")
       username = cleaned_data.get("username")

       if AccountAdmin.objects.filter(account=account, is_master=is_master).count() > 0:
           del cleaned_data["account"]
           del cleaned_data["is_master"]
           raise forms.ValidationError("Account and is_master combination already exists.")

       if AccountAdmin.objects.filter(account=account, username=username).count() > 0:
           del cleaned_data["account"]
           del cleaned_data["username"]
           raise forms.ValidationError("Account and username combination already exists.")

    # Always return the full collection of cleaned data.
    return cleaned_data

価値があるのは-上記のunique_togetherが、モデルで表されていないユーザー名と呼ばれるフィールドを参照していることに気付きました.

上記の clean メソッドは、個々のフィールドのすべての clean メソッドが呼び出された後に呼び出されます。

于 2009-12-17T19:32:32.887 に答える
2

そして、完全に一般的な方法です。モデルには、次の 2 つのヘルパー fn があります。

def getField(self,fieldName):
  # return the actual field (not the db representation of the field)
  try:
    return self._meta.get_field_by_name(fieldName)[0]
  except models.fields.FieldDoesNotExist:
    return None

def getUniqueTogether(self):
  # returns the set of fields (their names) that must be unique_together
  # otherwise returns None
  unique_together = self._meta.unique_together
  for field_set in unique_together:
    return field_set
  return None

フォームには次の fn があります。

def clean(self):
  cleaned_data = self.cleaned_data
  instance = self.instance

  # work out which fields are unique_together
  unique_filter = {}
  unique_fields = instance.getUniqueTogether()
  if unique_fields:
    for unique_field in unique_fields:
      field = instance.getField(unique_field)
      if field.editable: 
        # this field shows up in the form,
        # so get the value from the form
        unique_filter[unique_field] = cleaned_data[unique_field]
      else: 
        # this field is excluded from the form,
        # so get the value from the model
        unique_filter[unique_field] = getattr(instance,unique_field)

    # try to find if any models already exist in the db;
    # I find all models and then exlude those matching the current model.
    existing_instances = type(instance).objects.filter(**unique_filter).exclude(pk=instance.pk)

    if existing_instances:
      # if we've gotten to this point, 
      # then there is a pre-existing model matching the unique filter
      # so record the relevant errors
      for unique_field in unique_fields:
        self.errors[unique_field] = "This value must be unique."
于 2013-01-04T10:20:03.673 に答える
1

Model.Meta.unique_together はデータベースに限定された制約を作成しますが、ModelForm.is_valid() は主に正しい型に基づいています。制約をチェックした場合、競合状態が発生し、save() 呼び出しで引き続き IntegrityError が発生する可能性があります。

おそらく IntegrityError をキャッチしたいでしょう:

if new_accountadmin_form.is_valid():
    try:
        newaccountadmin_form.save()
    except IntegrityError, error:
        # here's your error handling code
于 2009-12-17T19:33:48.487 に答える