Django:如何从mod内部验证unique_

2024-04-29 16:23:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下资料:

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,其用户名与同一帐户上的另一个相同,而不是在模板中显示一个错误,而是用integriterror中断,页面将消失。我希望在我看来,我可以去:

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

我该如何克服这个问题。是否有第二种is_valid()类型的方法检查数据库是否违反了unique_together = (('Account', 'is_master'), ('Account', 'username'),)部分?

在我看来,我不想非得抓住一个整数错误。这是域逻辑和表示逻辑的混合。这违反了DRY,因为如果我在两页上显示相同的表单,我将不得不重复相同的块。这也违反了DRY,因为如果我有两种形式的同一件事,我必须写相同的除了:再次。


Tags: formmasternewismodels错误usernameaccount
3条回答

以一种完全通用的方式。在模型中有以下两个助手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."

有两种选择:

a)使用一个try块保存模型并捕获integriterror并处理它。类似于:

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。示例here


所以,b)是。。。这就是为什么我referenced the documentation; all you need is there.

但它会像:

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_引用了一个名为username的字段,这个字段在模型中没有表示。

上面的clean方法是在调用各个字段的所有clean方法之后调用的。

Model.Meta.unique_一起创建一个限制到数据库的约束,而ModelForm.is_valid()主要基于正确的类型。事件如果它确实检查了约束,则您将有一个竞赛条件,该条件仍可能在save()调用中导致IntegrityRor。

你可能想抓住整数错误:

if new_accountadmin_form.is_valid():
    try:
        newaccountadmin_form.save()
    except IntegrityError, error:
        # here's your error handling code

相关问题 更多 >