-
-
Save dminkovsky/4696559 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from django.utils.decorators import wraps | |
from django.core.exceptions import ValidationError | |
def constraint(func): | |
@wraps(func) | |
def inner(*args, **kwargs): | |
func._is_constraint = True | |
return func(*args, **kwargs) | |
return inner | |
class ConstraintModel(models.Model): | |
class Meta: | |
abstract = True | |
def _fill_constraints_cache(self): | |
cache = [] | |
for prop in dir(self): | |
_method = callable(getattr(self, prop)) | |
if getattr(_method, '_is_constraint', False): | |
cache.append(_method) | |
self._constraints_cache = tuple(cache) | |
def _constraints(self): | |
try: | |
self._constraints_cache | |
except AttributeError: | |
self._fill_constraints_cache() | |
return self._constraints_cache | |
constraints = property(_constraints) | |
def clean(self): | |
for constraint in self.constraints: | |
res = constraint() | |
if isinstance(basestring, res): | |
raise ValidationError('%s' % res) | |
self._cleaned = True | |
def save(self, *args, **kwargs): | |
# Do not run clean twice if was already done, but make sure it executes | |
# if it have not been called | |
if not hasattr(self, '_cleaned'): | |
self.clean() | |
super(ResourceModel, self).save(*args, **kwargs) | |
""" | |
Example: | |
- Create a model and extend from ConstraintModel | |
- Using the @constraint decorator register what tests to check | |
- Return a string to raise a validation Error | |
""" | |
class Loan(ConstraintModel): | |
user = models.ForeignKey('auth.User') | |
amount = models.IntegerField() | |
@constraint | |
def check_amount(self): | |
# Do not not lend less than 100 | |
if self.amount < 100: | |
# Return an error. | |
return 'Unable to lend less than 100$' | |
@constraint | |
def check_unpaid_loans(self): | |
# Do not not lend less than 100 | |
if self.user.total_unpaid_loans() > 1000: | |
return 'Not allowed, the user has already more than 1000$ in unpaid loans.' | |
@constraint | |
def check_luckyness(self): | |
import random | |
lucky = lambda p, m: True if m() < p else False | |
if not lucky(0.2, random.random): | |
return 'We are sorry, but after a detailed review we are unable to lend money to this user' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment