【问题标题】:How to create a Django FloatField with maximum and minimum limits?如何创建具有最大和最小限制的 Django FloatField?
【发布时间】:2012-05-19 07:44:00
【问题描述】:

我在我的 Django 模型中存储了一些浮点数据,并且只有特定范围的值是有意义的。因此,我想在模型和 SQL 约束级别施加这些限制。

例如,我想做这样的事情:

class Foo(Model):
   myfloat = FloatField(min=0.0, max=1.0)

我想在模型级别而不是表单级别执行此操作。实际上,我可能希望表单级别具有不同的范围;例如,在表单级别使用百分比 [0,100],但在模型中转换为 [0,1]。

这可能吗?如果可以,我将如何去做?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    到目前为止的答案描述了如何使表单验证。您还可以将验证器放入模型中。使用MinValueValidatorMaxValueValidator

    例如:

    from django.core.validators import MaxValueValidator, MinValueValidator
    
    ...
    weight = models.FloatField(
        validators=[MinValueValidator(0.0), MaxValueValidator(1.0)],
    )
    

    编辑

    但是,这不会添加 SQL 约束。

    您可以在Meta.constraints 中将here 中描述的SQL 约束添加为CheckConstraints。

    组合示例:

    from django.core.validators import MaxValueValidator, MinValueValidator
    from django.db.models import CheckConstraint, Q
    
    class Foo(Model):
        myfloat = FloatField(min=0.0, max=1.0,
            # for checking in forms
            validators=[MinValueValidator(0.0), MaxValueValidator(1.0)],)
    
        class Meta:
            constraints = (
                # for checking in the DB
                CheckConstraint(
                    check=Q(myfloat__gte=0.0) & Q(myfloat__lte=1.0),
                    name='foo_myfloat_range'),
                )
    

    【讨论】:

    • 然而,这些验证器不能在模型级别工作,至少不能自动工作。你可以保存一个weight 超出这些限制的模型。只是表单验证会自动选取这些验证器。
    • @AntonisChristofides 一年多之后,但我为 DB 约束添加了 CheckConstraint
    【解决方案2】:

    如果您需要对表单级别进行限制,您可以将min_valuemax_value 传递给form field

    myfloat = forms.FloatField(min_value=0.0, max_value=1.0)
    

    但如果您需要将其提升到模型级别,则必须扩展基础 models.FloatField

    class MinMaxFloat(models.FloatField):
        def __init__(self, min_value=None, max_value=None, *args, **kwargs):
            self.min_value, self.max_value = min_value, max_value
            super(MinMaxFloat, self).__init__(*args, **kwargs)
    
        def formfield(self, **kwargs):
            defaults = {'min_value': self.min_value, 'max_value' : self.max_value}
            defaults.update(kwargs)
            return super(MinMaxFloat, self).formfield(**defaults)
    

    然后就可以在模型中使用了

    class Foo(models.Model):
        myfloat = MinMaxFloat(min_value=0.0, max_value=1.0)
    

    【讨论】:

    • 好的。然后扩展 MinMaxFloat 以实际验证这些值并创建数据库约束,这取决于我吗?
    • 它在 django 模型级别创建约束,即您可以像 Foo(myfloat=-1.0).save() 一样手动插入记录,但是当您尝试根据您的 Foo 模型发送 ModelForm 时会收到 ValidationError
    【解决方案3】:

    已经有一段时间了,社区投票的答案已经足够好,基于 Django 内置,但这里有另一种方法,具体问题,遵循 Django Project's documentation

    创建自定义验证器

    # app/models.py or create another file for custom validators, i.e. app/custom_validators.py
    from django.core.exceptions import ValidationError
    from django.utils.translation import gettext_lazy as _  # use if you support internationalization
    
    def validate_interval(value):
        if value < 0.0 or value > 1.0:
            raise ValidationError(_('%(value)s must be in the range [0.0, 1.0]'), params={'value': value},)
    

    在模型中使用验证器

    # app/models.py
    
    class Foo(models.Model):
        myfloat = models.FloatField(validators=[validate_interval])
    

    您甚至可以使验证器参数更通用。

    编辑 - 重要

    请记住,在表单的 clean() 方法期间会调用任何验证器。

    I.E.如果您尝试在不使用表单的情况下直接创建对象,您的验证器将不会被调用。

    有些人不推荐它,但如果您想在创建对象时调用验证器,请覆盖 save 方法。

    # app/models.py
    
    from django.core.exceptions import ValidationError
    from django.utils.translation import gettext_lazy as _  # use if you support internationalization
    
    
    class Foo(models.Model):
        def save(self, *args, **kwargs):
            self.full_clean()  # or clean
            super().save(*args, **kwargs)
    
        def validate_interval(value):
            if value < 0.0 or value > 1.0:
                raise ValidationError(_('%(value)s must be in the range [0.0, 1.0]'), params={'value': value},)
    
        myfloat = models.FloatField(validators=[validate_interval])
    

    【讨论】:

    • 我在验证函数中放了一个记录器,但它没有运行
    • 请仔细阅读提供的资源。如果您阅读了我的原始答案中提供的链接,则可以清楚地看出验证器是在 ModelForm's clean() 方法中调用的。引用链接:Note that validators will not be run automatically when you save a model。我假设您尝试直接创建一个对象,即使用 save() 方法,因此永远不会调用验证器。如果您使用表单创建对象,则将使用验证器。否则,您可以覆盖 save() 方法。
    • 我理解为什么有人投反对票(因为这个问题非常具体),但这个答案确实是一个有用的补充,并给出了为什么你可能想要使用不同的验证方法的观点
    猜你喜欢
    • 2018-10-15
    • 1970-01-01
    • 2023-01-16
    • 1970-01-01
    • 2014-12-22
    • 2011-01-12
    • 1970-01-01
    • 2017-06-01
    • 2014-07-07
    相关资源
    最近更新 更多