Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write a Class-Based Django Validator?

I'm using Django 1.8.

The documentation on writing validators has an example of a function-based validator. It also says the following on using a class:

You can also use a class with a __call__() method for more complex or configurable validators. RegexValidator, for example, uses this technique. If a class-based validator is used in the validators model field option, you should make sure it is serializable by the migration framework by adding deconstruct() and __eq__() methods.

  • What are the pros/cons of class-based against function-based validators?
  • What is __call__() used for, and how is it used?
  • What is deconstruct() used for, and how is it used?
  • What is __eq__() used for, and how is it used?

An example would be helpful. A full answer may also be worth submitting to be in the official documentation.

Thanks!

like image 695
StringsOnFire Avatar asked Aug 21 '15 11:08

StringsOnFire


People also ask

How do you write class based views in Django?

Asynchronous class-based viewsimport asyncio from django. http import HttpResponse from django. views import View class AsyncView(View): async def get(self, request, *args, **kwargs): # Perform io-blocking view logic using await, sleep for example. await asyncio.

What is a validator class?

Validator class is a processor that checks an XML document against Schema. A validator object is not thread-safe and not reentrant.

How do I make a valid form in Django?

Django provides built-in methods to validate form data automatically. Django forms submit only if it contains CSRF tokens. It uses uses a clean and easy approach to validate data. The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class.

What is validator in Django?

A validator is a callable that takes a value and raises a ValidationError if it doesn't meet some criteria. Validators can be useful for reusing validation logic between different types of fields.


2 Answers

A big advantage of validator functions is that they are really simple. They simply take one value as an argument, check that it's valid, and and raise ValidationError if it's not. You don't need to worry about deconstruct and __eq__ methods to make migrations work.

The validate_even example in the docs is much simpler than a validator class would be.

def validate_even(value):
    if value % 2 != 0:
        raise ValidationError('%s is not an even number' % value)

If you need to check divisibility by other numbers as well, then it would be worth creating a validator class ValidateDivisibleBy. Then you could use ValidateDivisibleBy(2), ValidateDivisibleBy(3) and so on. But a lot of the time, a validator function is good enough.

like image 100
Alasdair Avatar answered Sep 30 '22 13:09

Alasdair


Other than being able to inherit from BaseValidator, there might not necessarily be a significant pro/con to choosing function vs class-based validators. I prefer class-based because you can keep internal state if necessary without making it visible to the clients (e.g. compiled regexes, pre-computed values in a table, history, etc.)

The __call__ method makes an object callable and allows it to sort of emulate function-like behavior (i.e. the object can be called like a function would), and the object's __call__ override will be invoked. It requires you to implement the special __call__(self, ...) method in the validator.

class Callable(object):
    def __call__(self,*args,**kwargs):
        print('Calling', args, kwargs)

>>> c = Callable()
>>> c(2, 3, color='red')
Calling (2, 3) {'color': 'red'}
>>>

The deconstruct method seems to provide a point where the client (i.e. you) can override serializing behavior by writing custom implementations. For example, see here. This seems similar to the clean method, where you can implement custom input sanitation for your models and gets called automatically when full_clean is invoked (e.g. when a form uses is_valid).

The __eq__ allows you to implement a comparison between 2 objects that are themselves not comparable. For example, if you have a

class Vector2:
    def __init__(self, x, y):
        self.x = x
        self.y = y

your __eq__ implementation could look like this to check for equality between two vector objects:

# ...
def __eq__(self, other):
    return self.x == other.x and self.y == other.y

This way, you avoid a shallow comparison of the underlying references.

like image 31
code_dredd Avatar answered Sep 30 '22 12:09

code_dredd