#22959 closed Cleanup/optimization (fixed)
Document that custom validator must be comparable to prevent infinite migrations
| Reported by: | Owned by: | Markus Holtermann | |
|---|---|---|---|
| Component: | Documentation | Version: | 1.7-rc-1 |
| Severity: | Normal | Keywords: | migrations |
| Cc: | Areski Belaid, info+coding@… | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I'm using a custom validator with a proper deconstruct on a TextField, it's intended to control the min and max number of words in the field. If I run python manage.py makemigrations over and over again it keeps generating the same migration related to changes on that text field, changes that do not exist.
Change History (11)
comment:1 by , 11 years ago
| Component: | Migrations → Documentation |
|---|---|
| Summary: | Custom validator in TextField → Document that custom validator must be comparable to prevent infinite migrations |
| Triage Stage: | Unreviewed → Accepted |
| Type: | Uncategorized → Cleanup/optimization |
comment:2 by , 11 years ago
I have been trying to reproduce this problem without luck!
Could you share a code sample where this could be reproduced?
This is how I tried to reproduce it:
from django.db import models
from django.core.exceptions import ValidationError
def validate_textlimit20chars(value):
if len(value) > 20:
raise ValidationError('%s is not an even number' % value)
class MyModel(models.Model):
name = models.CharField(max_length=32)
text20_field = models.TextField(default="", validators=[validate_textlimit20chars])
comment:3 by , 11 years ago
| Cc: | added |
|---|
comment:4 by , 11 years ago
Try a class-based validator like the ones for which an __eq__ method was added in the commit I linked in comment 1.
comment:5 by , 11 years ago
I'm trying to figure out how to make the class-based validator works, no luck: https://gist.github.com/areski/b9e293ad34d2b6845958
anyone can provide a working example?
comment:6 by , 11 years ago
Here's the original validator I used to get to know the problem (of course, by the time I discovered it there was no cmp)
class LimitWordsValidator:
def __init__(self, limit, upper=True):
self.limit = limit
self.upper = upper
def __cmp__(x, y):
return cmp(x.limit, y.limit) or cmp(x.upper, y.upper)
def __call__(self, value):
words = len(strip_tags(value).split())
args = {
'limit': self.limit,
'current': words,
}
if self.upper and words > self.limit:
raise ValidationError(_('You cannot exceed %(limit)s words, you have %(current)s.') % args)
if not self.upper and words < self.limit:
raise ValidationError(_('You need at least %(limit)s words, you have %(current)s.') % args)
def deconstruct(self):
return (
'common.validators.LimitWordsValidator',
[self.limit],
{'upper': self.upper},
)
comment:8 by , 11 years ago
| Cc: | added |
|---|---|
| Owner: | changed from to |
| Status: | new → assigned |
comment:9 by , 11 years ago
| Has patch: | set |
|---|
I added a pull request with documentation updates: https://github.com/django/django/pull/3271
comment:10 by , 11 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
This probably isn't an issue with Django itself but rather with your validator; they need to be comparable as in a68f32579145dfbd51d87e14f9b5e04c770f9081. However, we could add some docs about this since it will probably be a FAQ.