【问题标题】:Django model FloatField error 'float' object has no attribute 'as_tuple'Django模型FloatField错误'float'对象没有属性'as_tuple'
【发布时间】:2020-02-01 22:22:16
【问题描述】:

我有一个带有 FloatField 的 Django 模型,我稍后会基于它创建一个表单。出于某种原因,我得到“'float' object has no attribute 'as_tuple'”,不幸的是我不知道为什么会出现这个错误或如何修复它。

models.py:

class Course(models.Model):
    title = models.CharField(max_length = 200)
    author = models.ForeignKey(User,default=None, on_delete=models.SET_DEFAULT)
    description = models.TextField(max_length=1000, blank=True)
    tags = models.TextField(blank = True)
    duration = models.FloatField(validators=(MinValueValidator(0.1),MaxValueValidator(12), DecimalValidator(max_digits=3,decimal_places=2)))


    def __str__(self):
            return self.title

forms.py:

class CourseForm(ModelForm):
    class Meta:
        model = Course
        fields = ('title', 'description', 'price', 'duration', 'tags')

views.py:

@login_required
def create_course(request):
    if request.method == "POST":
        form = CourseForm(request.POST)

        if form.is_valid():

            form.save()
            messages.info(request, f"Course created succesfully!")

        else:
            messages.error(request, "Something went wrong, please resubmit!")


    form = CourseForm()
    return render(request, "main/createcourse.html", {"form": form})

html:

{% extends 'main/header.html' %}
<body>

   {% block content%}
<div class="container">

    <form method="POST">
        {% csrf_token %}

        {{form.as_p}}

        <br>
        <button class="btn" type="submit">Create</button>
    </form>

    If you to modify an existing course, click <a href="/modify"><strong>here</strong></a> instead.
</div>
<br><br>
    {% endblock %}



</body>

【问题讨论】:

  • 你不能对FloatField执行DecimalValidation,你应该使用DecimalField

标签: python django


【解决方案1】:

如果你真的需要使用FloatField,那么你需要编写自己的验证器:

def validate_decimals(value):
    s = str(value)
    d = decimal.Decimal(s)
    if abs(d.as_tuple().exponent) > 2:
        raise ValidationError(
            _('%(value)s has more than 2 decimals. Please enter 2 decimals only.'),
            params={'value': value},
        )

然后,在声明FloatField 时添加validators='validate_decimals'

请注意,浮点值不能直接转换为十进制。它应该首先转换为字符串,然后再转换为十进制。另见:

Python float to Decimal conversion

【讨论】:

    【解决方案2】:

    floatDecimal 之间存在差异。 Decimal 通过存储十进制数的数字来对数据进行编码。但是,您不能float 执行DecimalValidation,因为由于舍入错误,它会添加额外的数字。

    因此,您可以改用DecimalField [Django-doc]。请注意,在这种情况下,您需要传递 Decimal 对象,not 浮动。

    class Course(models.Model):
        title = models.CharField(max_length = 200)
        author = models.ForeignKey(User,default=None, on_delete=models.SET_DEFAULT)
        description = models.TextField(max_length=1000, blank=True)
        tags = models.TextField(blank = True)
        duration = models.DecimalField(max_digits=3,decimal_places=2, validators=(MinValueValidator(0.1),MaxValueValidator(12), DecimalValidator(max_digits=3,decimal_places=2)))
    
    
        def __str__(self):
                return self.title

    您可能想查看DurationField [Django-doc] 来存储持续时间,但是,这将自动使用timedelta,并将其存储为不支持此类类型的数据库的整数。 .

    【讨论】:

    • 这解决了问题,但现在 form.is_valid() 在有效数据上返回 false (例如: print(request.POST) : { 'title': ['test1'], 'description': ['test1'], 'duration': ['12'], 'tags': ['test1']}>)
    • @PetruTanas:由于您说最多三位数字和两位小数,因此“整数”位数最多为一位。因此,您应该使max_digits 更大。
    猜你喜欢
    • 2021-10-09
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-25
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多