Django在模型中提供了各种数字字段,例如DecimalField和PositiveIntegerField。虽然前者可以被限制为存储小数点后的位数和存储的字符总数,但是否有办法将其限制为仅存储某个范围内的数字,例如0.0-5.0 ?
如果做不到这一点,有没有办法限制PositiveIntegerField只存储,例如,最多50的数字?
更新:现在Bug 6845已经关闭,这个StackOverflow问题可能是没有意义的。——sampablokuper
Django在模型中提供了各种数字字段,例如DecimalField和PositiveIntegerField。虽然前者可以被限制为存储小数点后的位数和存储的字符总数,但是否有办法将其限制为仅存储某个范围内的数字,例如0.0-5.0 ?
如果做不到这一点,有没有办法限制PositiveIntegerField只存储,例如,最多50的数字?
更新:现在Bug 6845已经关闭,这个StackOverflow问题可能是没有意义的。——sampablokuper
当前回答
值得一提的是,有时候Django验证并不管用,因为Django验证主要是应用程序级的验证,而不是数据库级的验证。同样,模型验证不会在模型的保存/创建/更新过程中自动运行。如果你想在代码中立即验证你的值,那么你需要手动执行——使用override save()方法:
class UserRating():
SCORE_CHOICES = (
(1, _("Terrible")),
(2, _("Poor")),
(3, _("Average")),
(4, _("Very Good")),
(5, _("Excellent")),
)
score = models.PositiveSmallIntegerField(
choices=SCORE_CHOICES, default=1,
validators=[
MaxValueValidator(5),
MinValueValidator(1)
]
)
def save(self, *args, **kwargs):
if int(self.score) < 1 or int(self.score) > 5:
raise ValidationError('Score must be located between 0 to 5')
super(UserRating, self).save(*args, **kwargs)
...
其他回答
值得一提的是,有时候Django验证并不管用,因为Django验证主要是应用程序级的验证,而不是数据库级的验证。同样,模型验证不会在模型的保存/创建/更新过程中自动运行。如果你想在代码中立即验证你的值,那么你需要手动执行——使用override save()方法:
class UserRating():
SCORE_CHOICES = (
(1, _("Terrible")),
(2, _("Poor")),
(3, _("Average")),
(4, _("Very Good")),
(5, _("Excellent")),
)
score = models.PositiveSmallIntegerField(
choices=SCORE_CHOICES, default=1,
validators=[
MaxValueValidator(5),
MinValueValidator(1)
]
)
def save(self, *args, **kwargs):
if int(self.score) < 1 or int(self.score) > 5:
raise ValidationError('Score must be located between 0 to 5')
super(UserRating, self).save(*args, **kwargs)
...
你可以使用Django内置的验证器-
from django.db.models import IntegerField, Model
from django.core.validators import MaxValueValidator, MinValueValidator
class CoolModelBro(Model):
limited_integer_field = IntegerField(
default=1,
validators=[
MaxValueValidator(100),
MinValueValidator(1)
]
)
编辑:当直接使用模型时,请确保在保存模型之前调用模型full_clean方法,以便触发验证器。在使用ModelForm时,这不是必需的,因为表单将自动执行此操作。
我也有同样的问题;这是我的解决方案:
SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)
在forms.py中
Class FloatForm(forms.ModelForm):
class Meta:
model = Float
fields = ('name','country', 'city', 'point', 'year')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['point'] = forms.FloatField(max_value=100, min_value=1)
你也可以创建一个自定义的模型字段类型——参见http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields
在这种情况下,你可以“继承”内置的IntegerField并覆盖它的验证逻辑。
我越想这一点,就越意识到这对许多Django应用程序是多么有用。也许IntegerRangeField类型可以作为一个补丁提交给Django开发者,让他们考虑添加到trunk中。
这对我来说很管用:
from django.db import models
class IntegerRangeField(models.IntegerField):
def __init__(self, verbose_name=None, name=None, min_value=None, max_value=None, **kwargs):
self.min_value, self.max_value = min_value, max_value
models.IntegerField.__init__(self, verbose_name, name, **kwargs)
def formfield(self, **kwargs):
defaults = {'min_value': self.min_value, 'max_value':self.max_value}
defaults.update(kwargs)
return super(IntegerRangeField, self).formfield(**defaults)
然后在你的模型类中,你会像这样使用它(字段是你放置上面代码的模块):
size = fields.IntegerRangeField(min_value=1, max_value=50)
OR表示正负范围(如振荡器范围):
size = fields.IntegerRangeField(min_value=-100, max_value=100)
真正酷的是,如果它可以像这样用range操作符调用:
size = fields.IntegerRangeField(range(1, 50))
但是,这将需要更多的代码,因为你可以指定一个“skip”参数- range(1,50,2) -有趣的想法…