Python 如何限制Django模型中数值字段的最大值?

Python 如何限制Django模型中数值字段的最大值?,python,django,django-models,numbers,Python,Django,Django Models,Numbers,Django有各种数字字段可用于模型中,例如和。虽然前者可以限制为存储的小数位数和存储的字符总数,但是否有任何方法将其限制为仅存储特定范围内的数字,例如0.0-5.0 如果做不到这一点,有没有办法限制一个PositiveIntegerField只存储,例如最多50个数字 更新:现在有了Bug 6845,这个StackOverflow问题可能没有意义。-sampablokuper有两种方法可以做到这一点。一种是使用表单验证,绝不允许用户输入任何超过50的数字 如果过程中没有用户参与,或者您没有使用

Django有各种数字字段可用于模型中,例如和。虽然前者可以限制为存储的小数位数和存储的字符总数,但是否有任何方法将其限制为仅存储特定范围内的数字,例如0.0-5.0

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


更新:现在有了Bug 6845,这个StackOverflow问题可能没有意义。-sampablokuper有两种方法可以做到这一点。一种是使用表单验证,绝不允许用户输入任何超过50的数字


如果过程中没有用户参与,或者您没有使用表单输入数据,那么您必须覆盖模型的
save
方法以引发异常或限制数据进入字段。

您还可以创建自定义模型字段类型-请参阅

在这种情况下,您可以从内置IntegerField“继承”并重写其验证逻辑

我越想这一点,我就意识到这对许多Django应用程序是多么有用。也许一个整数字段类型可以作为Django DEVs的一个补丁来考虑添加到主干。 这对我有用:

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)
然后,在模型类中,您可以这样使用它(字段是放置上述代码的模块):

或对于正负范围(如振荡器范围):

真正酷的是,如果可以用range操作符调用它,如下所示:

size = fields.IntegerRangeField(range(1, 50))

但是,这将需要更多的代码,因为您可以指定一个“跳过”参数范围(1,50,2)-尽管这是一个有趣的想法…

我也遇到了同样的问题;以下是我的解决方案:

SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)
你可以用-


编辑:当直接使用模型时,确保在保存模型之前调用模型方法以触发验证程序。在使用
ModelForm
时,这不是必需的,因为表单将自动执行此操作。

如果您需要额外的灵活性并且不想更改模型字段,这里是最好的解决方案。只需添加此自定义验证程序:

from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator

size = models.IntegerField(validators=[MinValueValidator(0),
                                       MaxValueValidator(5)])
#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)
这两个参数是max和min,它允许空值。如果愿意,您可以通过去掉标记的if语句或在模型中将字段更改为blank=False、null=False来自定义验证器。这当然需要迁移

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

希望这有帮助:)更多关于

另外,我的答案基于django.core.validators中的BaseValidator,但除了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)

您也可以使用表单验证非人工输入。作为一种全方位的验证技术来填充表单非常有效。考虑到这一点,我很确定我不想将验证放在表单中。哪一个数字范围是可接受的问题与哪一类数字是可接受的问题一样,都是模型的一部分。我不想告诉每一个表单,通过它模型是可编辑的,只是哪一个数字范围可以接受。这会违反DRY,而且,这显然是不合适的。因此,我将研究重写模型的save方法,或者创建一个自定义模型字段类型——除非我能找到更好的方法:)tghw,你说我可以“重写模型的save方法以抛出异常或限制数据进入字段。”我该如何从模型定义的重写save()中开始方法-如果输入的数字超出给定范围,则用户会收到验证错误,就像她在数字字段中输入字符数据一样?也就是说,无论用户是通过管理员还是其他表单进行编辑,我是否有办法做到这一点?我不想只限制数据进入字段,而不告诉用户发生了什么:)谢谢!即使您使用“save”方法,在通过QuerySet更新表时也不起作用,比如MyModel.object.filter(blabla)。update(blabla)不会调用save,因此不会进行检查。您可以创建一个预保存信号:我应该提到,我还希望在Django的管理中应用该限制。为了实现这一点,文档中至少有这样一句话:实际上,1.0之前的Django似乎有一个非常优雅的解决方案:。我想知道在Django的svn版本中是否有一种同样优雅的方式来做到这一点。我很失望地获悉,目前的Django svn似乎没有一种优雅的方式来做到这一点。有关更多详细信息,请参阅此讨论线程:在模型上使用验证器,验证将在管理界面和ModelForms中工作:这可以工作,但在模型的clean方法中,整数的值始终为None,因此我无法对其进行任何额外的清理。知道这是为什么以及如何修复吗?在调用
super()之前,您可以通过添加
MinValueValidator(minu-value)和MaxValueValidator(max-value)
来增强自定义字段。如果希望有限的\u-integer\u字段也是可选的,我想您必须编写自己的验证器?(仅在不为空时验证范围)null=True,blank=True未执行此操作..在Django 1.7中,设置
null=True
blank=True
按预期工作。该字段是可选的,如果留空,则存储为空。使用列表理解:
models.IntegerField(选项=[(i,i)表示范围(1,n)],blank=True)
感谢您抽出时间回答这个问题。由于问题通常会得到多个答案(这个问题目前有七个答案),这是令人鼓舞的
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator

size = models.IntegerField(validators=[MinValueValidator(0),
                                       MaxValueValidator(5)])
#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)])
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)