2

This is my simple Django class:

class MyClass(models.Model):
    my_field1 = models.IntegerField(null=False,blank=False,) 

    # I want to insert validation rule such that my_field2 = True iff my_field1 > 10
    my_field2 = models.BooleanField(null=False, blank=False,)

I would like to insert validation rule such that my_field2 = True iff my_field1 > 10. If the user enters data that violates that constraint, I would like the constructor to raise an exception.

#MyClass.object.create(9, False)     # Should Succeed
#MyClass.object.create(11, True)     # Should Succeed
#MyClass.object.create(31, True)     # Should Succeed
#MyClass.object.create(8, True)      # Should Throw exception
#MyClass.object.create(21, False)    # Should Throw exception

How can I do it? Everything I have read about django validation occurs in the model form. But my application has no forms. I need the validation in the model itself. How can I do that?

3
  • 1
    Take a look at pre-save signals. Commented Jul 29, 2015 at 18:42
  • have a look at this on Django's docs Commented Jul 29, 2015 at 18:49
  • Pynchia, that doesn't solve the problem because the clean methods are not automatically called when I do MyClass.object.create() Commented Jul 29, 2015 at 18:51

4 Answers 4

3

Following the answer here. I think you are looking for something like this:

from django.db import models
from django.core.validators import MinValueValidator

class MyClass(models.Model):
    my_field1 = IntegerField(
        validators=[MinValueValidator(11)]
    )
Sign up to request clarification or add additional context in comments.

4 Comments

You're right, this is something like what I'm looing for. However, This shows how to do simple min and max validation. I want to do something more complex. How can I do custom validation? And it has to use the values of the other parameters being sent in (as described in my original question)
It sounds like you want to write a custom validator. You can read about them here: docs.djangoproject.com/en/1.8/ref/validators
EricBulloch, but can those custom validators validate based on the values of the other fields coming into the constructor? From the link you posted, it doesn't seem so.
@SaqibAli According to the link the validators are not ran when a model is saved docs.djangoproject.com/en/1.8/ref/validators/…. It looks like you will have to do something like override the save function as well.
1

You can attach a pre_save signal and check if those two values are satisfying your constraints.

from django.core.exceptions import ValidationError
from django.db.models.signals import pre_save
from django.dispatch import receiver

@receiver(pre_save, sender=MyClass)
def model_pre_save(sender, instance, **kwargs):
    if ((instance.my_field1 >= 10 and not instance.my_field2) or
        (instance.my_field1 < 10 and instance.my_field2)):
        raise ValidationError('Validation error: {}'.format(instance))

Comments

0

Django provides Model Validation options with one gotcha: they don't fire by default, so you have to override the model's save() method to call clean/ full_clean like so:

def save(self, *args, **kwargs):
    self.full_clean()
    super(MyClass, self).save(*args, **kwargs)

Comments

0

Why you dont use the Form layer? You could use the form layer as a "validation" layer only, it means, dont use it to render an HTML. Its pretty common to use the Form layer even on JSON API or AJAX.

For example, you could use a form as follow:

def my_ajax_view(request, pk):
    ret = {'success': False, 'errors': []}
    instance = get_object_or_404(MyModel, pk=pk)
    f = ModelUpdateForm(request.POST, instance=ins)
    if f.is_valid():
        #your code
        ret['success'] = True
        return JSONResponse(ret)

    ret['errors'] = serialize_form_errors(f)  #not in django
    return JSONResponse(ret)

Other approach could be re-implement the save() method, as explained in @tom's comment.

Thanks!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.