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

sam*_*per 144 python django numbers django-models

Django有各种可用于模型的数字字段,例如DecimalFieldPositiveIntegerField.虽然前者可以限制在存储小数位的数量和字符的存储总数,有没有办法将其限制于存储在一定范围内的数字,如0.0-5.0?

如果失败了,有没有办法限制一个PositiveIntegerField只存储,例如,最多50个数字?

更新:现在Bug 6845 已经关闭,这个StackOverflow问题可能没什么问题. - sampablokuper

use*_*050 293

你可以使用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)
        ]
     )
Run Code Online (Sandbox Code Playgroud)

编辑:虽然这些仅在您在ModelForm中使用模型时有效,但如果您" 单独使用"模型,则不会感叹.

  • 如果你想让limited_integer_field也是可选的,我想你必须编写自己的验证器吗?(只有Validate范围,如果不是空白)null = True,blank = True没有这样做.. (4认同)
  • 在Django 1.7中,设置`null = True`和`blank = True`可以正常工作。该字段是可选的,如果保留为空白,则存储为null。 (2认同)

Nat*_*anD 127

您还可以创建自定义模型字段类型 - 请参阅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)
Run Code Online (Sandbox Code Playgroud)

然后在你的模型类中,你会像这样使用它(字段是放置上面代码的模块):

size = fields.IntegerRangeField(min_value=1, max_value=50)
Run Code Online (Sandbox Code Playgroud)

或者对于一系列的负面和正面(如振荡器范围):

size = fields.IntegerRangeField(min_value=-100, max_value=100)
Run Code Online (Sandbox Code Playgroud)

如果可以使用范围运算符调用它,那真的很酷:

size = fields.IntegerRangeField(range(1, 50))
Run Code Online (Sandbox Code Playgroud)

但是,这需要更多代码,因为你可以指定'skip'参数 - 范围(1,50,2) - 尽管有趣的想法......

  • 您可以通过在调用 `super().__init__ ...` 之前添加`MinValueValidator(min_value) 和 MaxValueValidator(max_value)` 来增强自定义字段(代码片段:https://gist.github.com/madneon/147159f46ed478c71d5ee4950a9d697d) (2认同)

小智 70

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

size = models.IntegerField(validators=[MinValueValidator(0),
                                       MaxValueValidator(5)])
Run Code Online (Sandbox Code Playgroud)


小智 50

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

SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)
Run Code Online (Sandbox Code Playgroud)

  • 使用列表推导:`models.IntegerField(choices = [(i,i)for i in range(1,n)],blank = True) (9认同)

tgh*_*ghw 10

有两种方法可以做到这一点.一种是使用表单验证,绝不允许用户输入超过50的任何数字.表单验证文档.

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

  • 您也可以使用表单来验证非人类输入.它非常适合将Form填充为全面的验证技术. (2认同)

rad*_*tek 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)
Run Code Online (Sandbox Code Playgroud)

它可以这样使用:

class YourModel(models.Model):

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

两个参数是max和min,它允许为空。您可以根据需要通过删除标记的if语句来自定义验证器,或者在模型中将字段更改为blank = False,null = False。当然,这将需要迁移。

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

希望对您有所帮助:)有关Django中的Validators的更多信息。

PS。我的答案基于django.core.validators中的BaseValidator,但除代码外,其他所有内容都不同。