Extra django model validation.
Project description
django-dynamic-model-validation
Introduction
When faced with a need to implement reusable validation logic for forms and models. This package aims to provide tools needed to define validation logic once which can be leveraged using django forms, test case, API implementation or any model operation that requires saving data to the database.
This can also be extended by defining table check constraints if needed but currently validation will only be handled at the model level.
Installation
django-dynamic-model-validation is distributed on PyPI as a universal wheel and is available on Linux/macOS and Windows and supports Python 2.7/3.5+ and PyPy.
$ pip install django-dynamic-model-validation
INSTALLED_APPS = [
...
'dynamic_validator',
]
Usage
This provides model level validation which includes conditional validation, cross field validation, required field validation etc.
This is done using model attributes below.
# Using a list/iterable list: [['a', 'b'], ['c', 'd']] which validates that a field required from each section.
REQUIRED_TOGGLE_FIELDS = []
# Using a list/iterable validated that all required fields are provided.
REQUIRED_FIELDS = []
# Optional toggle fields list: [['a', 'b']] which runs the validation only when any of the fields are present.
OPTIONAL_TOGGLE_FIELDS = []
# Conditional field validation using a list of tuples the condition a boolean or a callable and list/iterable of fields.
# [(condition, [fields]), (condition, fields)]
# Using a callable [(lambda instance: instance.is_admin, ['a', 'd'])]
# Using a boolean [(True, ['b', 'c']), (True, ['d', f])] (Note: This can be better handled using REQUIRED_FIELDS/REQUIRED_TOGGLE_FIELDS)
# Validates that all fields are present if the condition is True
CONDITIONAL_REQUIRED_FIELDS = []
# Validated at least one not both fields are provided if the condition is True.
CONDITIONAL_REQUIRED_TOGGLE_FIELDS = []
[Validates] That only one of the fields should be provided.
from django.db import models
from dynamic_validator import ModelFieldRequiredMixin
class TestModel(ModelFieldRequiredMixin, models.Model):
amount = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
fixed_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
percentage = models.DecimalField(max_digits=3, decimal_places=0, null=True, blank=True)
REQUIRED_TOGGLE_FIELDS = [
['amount', 'fixed_price', 'percentage'],
]
$ python manage.py shell
...
>>> from decimal import Decimal
>>> from demo.models import TestModel
>>> TestModel.objects.create(amount=Decimal('2.50'), fixed_price=Decimal('3.00'))
...
ValueError: {'fixed_price': ValidationError([u'Please provide only one of: Amount, Fixed price, Percentage'])}
[Validates] That a field without a default is required.
from django.db import models
from dynamic_validator import ModelFieldRequiredMixin
class TestModel(ModelFieldRequiredMixin, models.Model):
amount = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
fixed_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
percentage = models.DecimalField(max_digits=3, decimal_places=0, null=True, blank=True)
REQUIRED_FIELDS = ['amount'] # Always requires an amount to create the instance.
$ python manage.py shell
...
>>> from decimal import Decimal
>>> from demo.models import TestModel
>>> TestModel.objects.create(fixed_price=Decimal('3.00'))
...
ValueError: {'amount': ValidationError([u'Please provide a value for: "amount".'])}
[Validates] That an instance can be created without optional fields but should only have one value if any of the optional fields are provided.
from django.db import models
from dynamic_validator import ModelFieldRequiredMixin
class TestModel(ModelFieldRequiredMixin, models.Model):
amount = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
fixed_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
percentage = models.DecimalField(max_digits=3, decimal_places=0, null=True, blank=True)
OPTIONAL_TOGGLE_FIELDS = [
['fixed_price', 'percentage'] # Optionally validates that only fixed price/percentage are provided.
]
$ python manage.py shell
...
>>> from decimal import Decimal
>>> from demo.models import TestModel
>>> first_obj = TestModel.objects.create(amount=Decimal('2.0'))
>>> second_obj = TestModel.objects.create(amount=Decimal('2.0'), fixed_price=Decimal('3.00'))
>>> third_obj = TestModel.objects.create(amount=Decimal('2.0'), fixed_price=Decimal('3.00'), percentage=Decimal('10.0'))
...
ValueError: {'percentage': ValidationError([u'Please provide only one of: Fixed price, Percentage'])}
[Validates] That if the user is active (ie. instance.user.is_active) both fields should be provided.
from django.db import models
from django.conf import settings
from dynamic_validator import ModelFieldRequiredMixin
class TestModel(ModelFieldRequiredMixin, models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
amount = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
fixed_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
percentage = models.DecimalField(max_digits=3, decimal_places=0, null=True, blank=True)
CONDITIONAL_REQUIRED_FIELDS = [
(
lambda instance: instance.user.is_active, ['amount', 'percentage'],
),
]
$ python manage.py shell
...
>>> from decimal import Decimal
>>> from django.contrib.auth import get_user_model
>>> from demo.models import TestModel
>>> user = get_user_model().objects.create(username='test', is_active=True)
>>> first_obj = TestModel.objects.create(user=user, amount=Decimal('2.0'))
...
ValueError: {u'percentage': ValidationError([u'Please provide a value for: "percentage"'])}
[Validates] That if the user is active (ie. instance.user.is_active) any of the fields should be provided (i.e only one).
from django.db import models
from django.conf import settings
from dynamic_validator import ModelFieldRequiredMixin
class TestModel(ModelFieldRequiredMixin, models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
amount = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
fixed_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
percentage = models.DecimalField(max_digits=3, decimal_places=0, null=True, blank=True)
CONDITIONAL_REQUIRED_TOGGLE_FIELDS = [
(
lambda instance: instance.user.is_active, ['fixed_price', 'percentage', 'amount'],
),
]
$ python manage.py shell
...
>>> from decimal import Decimal
>>> from django.contrib.auth import get_user_model
>>> from demo.models import TestModel
>>> user = get_user_model().objects.create(username='test', is_active=True)
>>> first_obj = TestModel.objects.create(user=user)
...
ValueError: {'__all__': ValidationError([u'Please provide a valid value for any of the following fields: Fixed price, Percentage, Amount'])}
...
>>>first_obj = TestModel.objects.create(user=user, amount=Decimal('2'), fixed_price=Decimal('2'))
...
ValueError: {'__all__': ValidationError([u'Please provide only one of the following fields: Fixed price, Percentage, Amount'])}
...
License
django-dynamic-model-validation is distributed under the terms of both
at your option.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for django-dynamic-model-validation-0.1.3.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 72903b484acb8cf6d144068ed54d940d89e34d9b4bbc707f117ac6c0bc1853e8 |
|
MD5 | 69c372b5dec5dca9444f51386ddd34a1 |
|
BLAKE2b-256 | 90306ebb37a78b6e5254176c6b9748d306e3e293ecdfd2ebe868f67c627fa49c |
Hashes for django_dynamic_model_validation-0.1.3-py2-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | aa92b7cf5c8801cc7271567e7419cb3cd1a5074e31de330f9f1390c676011965 |
|
MD5 | 8899cbe2d6625675c97be7856e1a972f |
|
BLAKE2b-256 | da99c828030e4116cb8453bd7029565a310fe6ed8202fdf41228fb939c37bfeb |