Django 1.8.3 - 使用相关对象进行模型字段验证

时间:2020-12-23 19:34:37

For the following set of models (Foo, Bar), you could impose a cross-validation rule like the one in the Bar.clean of the following code snippet up to django 1.7.

对于以下模型集(Foo,Bar),您可以将以下代码段的Bar.clean中的交叉验证规则强加到django 1.7。

The same snippet throws a RelatedObjectDoesNotExist error in django 1.8.3.

相同的代码片段在django 1.8.3中引发了一个RelatedObjectDoesNotExist错误。

What is the new and improved way of achieving the same result in django 1.8.3?

在django 1.8.3中实现相同结果的新方法和改进方法是什么?

(I've included the admin.py code just to show how these models are being used.)

(我已经包含了admin.py代码,仅用于说明如何使用这些模型。)

models.py

from django.db import models
from django.core.exceptions import ValidationError

class Foo(models.Model):
   name = models.CharField("Name", blank=True, max_length=300)

class Bar(models.Model):
   name = models.CharField("Name", blank=True, max_length=300)
   foo = models.ForeignKey('Foo', verbose_name='Foo')

   def clean(self):
      if self.name + self.foo.name != 'FooBar':
         raise ValidationError('Concatenation should be FooBar.')

admin.py

from django.contrib import admin
import models

class BarInline(admin.TabularInline):
    model = models.Bar

class FooAdmin(admin.ModelAdmin):
    model = models.Foo
    inlines = [BarInline,]

site = admin.site
site.register(models.Foo,FooAdmin)

1 个解决方案

#1


1  

I've added a simple output modification to your code

我在代码中添加了一个简单的输出修改

def clean(self):
  print(self.__dict__)

  if self.name + self.foo.name != 'FooBar':
     raise ValidationError('Concatenation should be FooBar.')

The simple print statements will print out Bar object before executing of main code.

简单的print语句将在执行主代码之前打印出Bar对象。

Now I've tested the code with Django 1.8.x and I've got the exception as you mentioned this is the result:

现在我用Django 1.8.x测试了代码,我得到了例外,因为你提到这是结果:

{'_state': <django.db.models.base.ModelState object at 0x7ff55cd30710>, 'id': None, 'foo_id': None, 'name': 'Bar 1'}

Now I've tested it again with Django 1.7.x and it works ok, the output result is:

现在我用Django 1.7.x再次测试它并且它工作正常,输出结果是:

{'_foo_cache': <Foo: Foo object>, 'name': 'Bar 1', 'id': None, 'foo_id': None, '_state': <django.db.models.base.ModelState object at 0x7f731151c9e8>}

As you may noticed the foo_id in both cases in None but what does the magic is the _foo_cache thing that was removed in Django 1.8

您可能已经注意到两种情况下的foo_id都是None,但魔术是Django 1.8中删除的_foo_cache。

The substitute that I can suggest you is to move your validation into Forms

我建议你的替代方法是将你的验证转移到表格中

Made these changes : admin.py

做了这些更改:ad​​min.py

class BarInline(admin.TabularInline):
    model = Bar
    form = BarForm

forms.py

class BarForm(forms.models.ModelForm):
    class Meta:
        model = Bar
        fields = ('name',)

    def clean(self):
      data = self.cleaned_data     
      if not data['name'] + data['foo'].name == "foobar":
         raise ValidationError('Concatenation should be FooBar.')

#1


1  

I've added a simple output modification to your code

我在代码中添加了一个简单的输出修改

def clean(self):
  print(self.__dict__)

  if self.name + self.foo.name != 'FooBar':
     raise ValidationError('Concatenation should be FooBar.')

The simple print statements will print out Bar object before executing of main code.

简单的print语句将在执行主代码之前打印出Bar对象。

Now I've tested the code with Django 1.8.x and I've got the exception as you mentioned this is the result:

现在我用Django 1.8.x测试了代码,我得到了例外,因为你提到这是结果:

{'_state': <django.db.models.base.ModelState object at 0x7ff55cd30710>, 'id': None, 'foo_id': None, 'name': 'Bar 1'}

Now I've tested it again with Django 1.7.x and it works ok, the output result is:

现在我用Django 1.7.x再次测试它并且它工作正常,输出结果是:

{'_foo_cache': <Foo: Foo object>, 'name': 'Bar 1', 'id': None, 'foo_id': None, '_state': <django.db.models.base.ModelState object at 0x7f731151c9e8>}

As you may noticed the foo_id in both cases in None but what does the magic is the _foo_cache thing that was removed in Django 1.8

您可能已经注意到两种情况下的foo_id都是None,但魔术是Django 1.8中删除的_foo_cache。

The substitute that I can suggest you is to move your validation into Forms

我建议你的替代方法是将你的验证转移到表格中

Made these changes : admin.py

做了这些更改:ad​​min.py

class BarInline(admin.TabularInline):
    model = Bar
    form = BarForm

forms.py

class BarForm(forms.models.ModelForm):
    class Meta:
        model = Bar
        fields = ('name',)

    def clean(self):
      data = self.cleaned_data     
      if not data['name'] + data['foo'].name == "foobar":
         raise ValidationError('Concatenation should be FooBar.')