Django在模型中提供了各种数字字段,例如DecimalField和PositiveIntegerField。虽然前者可以被限制为存储小数点后的位数和存储的字符总数,但是否有办法将其限制为仅存储某个范围内的数字,例如0.0-5.0 ?

如果做不到这一点,有没有办法限制PositiveIntegerField只存储,例如,最多50的数字?

更新:现在Bug 6845已经关闭,这个StackOverflow问题可能是没有意义的。——sampablokuper


当前回答

我也有同样的问题;这是我的解决方案:

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) -有趣的想法…

有两种方法。一种是使用表单验证,不允许用户输入任何超过50的数字。表单验证文档。

如果流程中没有用户参与,或者没有使用表单输入数据,那么必须重写模型的save方法来抛出异常或限制进入字段的数据。

在models.py中的model列中添加如下验证器

class Planogram(models.Model):
    camera = models.ForeignKey(Camera, on_delete=models.CASCADE)
    xtl = models.DecimalField(decimal_places=10, max_digits=11,validators=[MaxValueValidator(1),MinValueValidator(0)])

如果你使用create函数来创建对象,将其更改为如下....的构造函数 并在该对象上调用fullclean(),然后保存.. 一切都会完美无缺。

planogram = Planogram(camera_id = camera,xtl=xtl,ytl=ytl,xbr=xbr,ybr=ybr,product_id=product_id)
planogram.full_clean()
planogram.save()

如果你想要一些额外的灵活性并且不想改变你的模型字段,下面是最好的解决方案。只需添加这个自定义验证器:

#Imports
from django.core.exceptions import ValidationError      

class validate_range_or_null(object):
    compare = lambda self, a, b, c: a > c or a < b
    clean = lambda self, x: x
    message = ('Ensure this value is between %(limit_min)s and %(limit_max)s (it is %(show_value)s).')
    code = 'limit_value'

    def __init__(self, limit_min, limit_max):
        self.limit_min = limit_min
        self.limit_max = limit_max

    def __call__(self, value):
        cleaned = self.clean(value)
        params = {'limit_min': self.limit_min, 'limit_max': self.limit_max, 'show_value': cleaned}
        if value:  # make it optional, remove it to make required, or make required on the model
            if self.compare(cleaned, self.limit_min, self.limit_max):
                raise ValidationError(self.message, code=self.code, params=params)

它可以这样使用:

class YourModel(models.Model):

    ....
    no_dependents = models.PositiveSmallIntegerField("How many dependants?", blank=True, null=True, default=0, validators=[validate_range_or_null(1,100)])

这两个参数是max和min,它允许为空。如果您愿意,您可以通过去掉标记的if语句或将您的字段更改为模型中的blank=False, null=False来定制验证器。这当然需要迁移。

注意:我必须添加验证器,因为Django不验证PositiveSmallIntegerField的范围,而是为这个字段创建一个smallint(在postgres中),如果指定的数字超出了范围,你会得到一个DB错误。

希望这有助于:)更多关于Django中的验证器。

另外,我的答案是基于django.core中的BaseValidator。验证器,但除了代码以外,一切都不同。