We are using Django (currently 1.11.15) for Speedy Net and Speedy Match. Recently I found out that django.db.models.Model save() method doesn't call full_clean(). I read about it a little (for example on Why doesn't django's model.save() call full_clean()?) and decided it's a better programming practice to call self.full_clean() before saving the model. I implemented it with class ValidateModelMixin (from 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)And then inherit from it in my base model class (which all models inherit from):
class BaseModel(ValidateModelMixin, models.Model):But the problem is, most of my tests fail with this message:
====================================================================== 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.']} ----------------------------------------------------------------------I think the problem is with this class we defined, and specifically with how we defined the password:
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(1900, 1, 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 = UserIs there a better way to define this class so the tests will pass?
Thanks,
|
Hi,I noticed that django.db.models.Model save method doesn't call self.full_clean(). Is it a good practice to call self.full_clean() in my own models (which subclass django.db.models.Model) save method before calling "super().save(*args, **kwargs)"? I tried to add it in my models but I received many errors in tests: ============================================================ ========== 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 19, in saveself.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.']} ------------------------------------------------------------ ---------- This is due to how we defined 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(1900, 1, 1)) gender = User.GENDER_OTHERslug = 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 = UserFormerly the password defined there was invalid (too short, '111', see https://github.com/urievenchen/speedy-net/blob/ ) and I want all fields to be validated before they are saved to the database. What is the best method to achieve this?master/speedy/core/accounts/ tests/test_factories.py Thanks,Uri.
Uri Even-Chen
![]()
Phone: +972-54-3995700
Email: uri@speedy.net
Website: http://www.speedysoftware.com/uri/en/
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAMQ2MsEt7%3DxCbPqN6KgRCE_WPYhEvMjhy_4ai722HZDZiSthfg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
No comments:
Post a Comment