在模型save()中调用self.full_clean()时出现问题

时间:2018-08-07 14:41:57

标签: python django django-models django-validation

我们在Speedy Net and Speedy Match中使用Django(当前为1.11.15)。最近,我发现django.db.models.Model save()方法没有调用full_clean()。我了解了一点(例如在Why doesn't django's model.save() call full_clean()?上),并认为在保存模型之前调用self.full_clean()是一种更好的编程习惯。我用class ValidateModelMixin(来自Django model mixin to force Django to validate (i.e. call full_clean) before save)实现了它:

class ValidateModelMixin(object):
    def save(self, *args, **kwargs):
        """Call `full_clean` before saving."""
        self.full_clean()
        return super().save(*args, **kwargs)

然后在我的基础模型类(所有模型都从中继承)中继承:

class BaseModel(ValidateModelMixin, models.Model):

但是问题是,我的大多数测试都失败,并显示以下消息:

======================================================================
ERROR: test_user_gets_redirected_to_his_profile (speedy.net.accounts.tests.test_views.IndexViewTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "speedy\net\accounts\tests\test_views.py", line 8, in setUp
    self.user = ActiveUserFactory()
  File "VENV~1\lib\site-packages\factory\base.py", line 46, in __call__
    return cls.create(**kwargs)
  File "VENV~1\lib\site-packages\factory\base.py", line 563, in create
    return cls._generate(enums.CREATE_STRATEGY, kwargs)
  File "VENV~1\lib\site-packages\factory\base.py", line 500, in _generate
    return step.build()
  File "VENV~1\lib\site-packages\factory\builder.py", line 279, in build
    kwargs=kwargs,
  File "VENV~1\lib\site-packages\factory\base.py", line 314, in instantiate
    return self.factory._create(model, *args, **kwargs)
  File "VENV~1\lib\site-packages\factory\django.py", line 165, in _create
    return manager.create(*args, **kwargs)
  File "VENV~1\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "VENV~1\lib\site-packages\modeltranslation\manager.py", line 405, in create
    return super(MultilingualQuerySet, self).create(**kwargs)
  File "VENV~1\lib\site-packages\django\db\models\query.py", line 394, in create
    obj.save(force_insert=True, using=self.db)
  File "speedy\core\accounts\models.py", line 52, in save
    return super().save(*args, **kwargs)
  File "speedy\core\base\models.py", line 27, in save
    return super().save(*args, **kwargs)
  File "speedy\core\base\models.py", line 12, in save
    self.full_clean()
  File "VENV~1\lib\site-packages\django\db\models\base.py", line 1250, in full_clean
    raise ValidationError(errors)
django.core.exceptions.ValidationError: {'password': ['This field cannot be blank.']}

----------------------------------------------------------------------

我认为问题在于我们定义的此类,特别是我们定义密码的方式:

class DefaultUserFactory(factory.DjangoModelFactory):
    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
    date_of_birth = factory.fuzzy.FuzzyDate(start_date=date(year=1900, month=1, day=1))
    gender = User.GENDER_OTHER
    slug = factory.fuzzy.FuzzyText(chars=string.ascii_lowercase)
    username = factory.LazyAttribute(lambda o: normalize_username(slug=o.slug))
    password = factory.PostGenerationMethodCall(method_name='set_password', raw_password=USER_PASSWORD)

    class Meta:
        model = User

是否有更好的方法定义此类,以便测试通过?

1 个答案:

答案 0 :(得分:0)

我通过这样定义class DefaultUserFactory找到了解决方案:

class DefaultUserFactory(factory.DjangoModelFactory):
    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
    date_of_birth = factory.fuzzy.FuzzyDate(start_date=date(year=1900, month=1, day=1))
    gender = User.GENDER_OTHER
    slug = factory.fuzzy.FuzzyText(chars=string.ascii_lowercase)
    username = factory.LazyAttribute(lambda o: normalize_username(slug=o.slug))
    password = factory.fuzzy.FuzzyText(chars=string.ascii_lowercase)
    _password = factory.PostGenerationMethodCall(method_name='set_password', raw_password=USER_PASSWORD)

    class Meta:
        model = User