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

问题描述 投票:0回答:10

Django 有各种可在模型中使用的数字字段,例如DecimalFieldPositiveIntegerField。虽然前者可以限制存储的小数位数和存储的字符总数,但有什么方法可以限制它只存储一定范围内的数字,例如0.0-5.0? 如果做不到这一点,有没有办法限制 PositiveIntegerField 仅存储例如最大 50 的数字?

更新:既然 Bug 6845 已被关闭,这个 StackOverflow 问题可能没有实际意义。 - sampablokuper

python django django-models limit django-validation
10个回答
497
投票
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 时不需要这样做,因为表单会自动执行此操作。

    


146
投票
http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields

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

我思考得越多,我意识到这对于许多 Django 应用程序来说是多么有用。也许 IntegerRangeField 类型可以作为补丁提交,供 Django 开发人员考虑添加到主干。

这对我有用:

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)

如果可以像这样使用范围运算符来调用它,那就太酷了:

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

但是,这将需要更多的代码,因为您可以指定“跳过”参数 - range(1, 50, 2) - 不过有趣的想法......


106
投票


57
投票

SCORE_CHOICES = zip( range(1,n), range(1,n) ) score = models.IntegerField(choices=SCORE_CHOICES, blank=True)



10
投票
表单验证文档

如果没有用户参与该过程,或者您没有使用表单输入数据,那么您必须重写模型的

save

方法以引发异常或限制进入该字段的数据。

    


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)])

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

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

希望这会有所帮助:) 有关

Django 中的验证器

的更多信息。 PS。我的答案基于 django.core.validators 中的 BaseValidator,但除了代码之外,一切都不同。


0
投票

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)



0
投票
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)
    
    ...



0
投票

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()



0
投票
models.DecimalField()

models.PositiveIntegerField() 使用 MaxValueValidator()MinValueValidator() 来设置值的可用范围,如下所示: # "models.py" from django.db import models from django.core.validators import MaxValueValidator, MinValueValidator class Test(models.Model): num1 = models.DecimalField( max_digits=3, decimal_places=1, validators=[ MaxValueValidator(10.0), MinValueValidator(0.0) ], ) num2 = models.PositiveIntegerField( validators=[ MaxValueValidator(10), MinValueValidator(0) ], )

最后,您最好使用 
forms.DecimalField()

forms.IntegerField()
覆盖
num1
num2 字段,以设置 Django Admin 中值的可用范围,如下所示: from django.contrib import admin from .models import Test from django import forms class TestForm(forms.ModelForm): num1 = forms.DecimalField( max_value=10.0, min_value=0.0, step_size=0.1 ) num2 = forms.IntegerField( max_value=10, min_value=0 ) @admin.register(Test) class TestAdmin(admin.ModelAdmin): form = TestForm

此外,下面带有 
forms.NumberInput

的代码与上面的代码相同: from django.contrib import admin from .models import Test from django import forms class TestForm(forms.ModelForm): num1 = forms.DecimalField( widget=forms.NumberInput(attrs={'max': 10.0, 'min': 0.0, 'step': 0.1}) ) num2 = forms.IntegerField( widget=forms.NumberInput(attrs={'max': 10, 'min': 0}) ) @admin.register(Test) class TestAdmin(admin.ModelAdmin): form = TestForm

© www.soinside.com 2019 - 2024. All rights reserved.