Reputation: 1237
I have a Django model with a FloatField, which I later base a form on. For some reason I get "'float' object has no attribute 'as_tuple'", and unfortunately I have no idea why do I get this error or how to fix it.
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>
Upvotes: 1
Views: 1787
Reputation: 21
If you really need to use a FloatField
, then you need to write your own validator:
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},
)
Then, you add validators='validate_decimals'
when you declare the FloatField
.
Note that a float value cannot directly be converted to decimal. It should first be converted to string and then to decimal. See also:
Python float to Decimal conversion
Upvotes: 2
Reputation: 476544
There is a difference between a float
and a Decimal
. A Decimal
encodes the data by storing the digits of a decimal number. You can however not perform DecimalValidation
on a float
, since due to rounding errors, it will add extra digits.
You thus can use a DecimalField
[Django-doc] instead. Note that you thus need to pass Decimal
objects in that case, not floats.
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
You might want to take a look at the DurationField
[Django-doc] to store duration however, this will automatically use a timedelta
, and store it as an integer for databases that do not support such types.
Upvotes: 1