使用Django的DecimalField与Select Widget

huangapple go评论130阅读模式
英文:

Using Django DecimalField with Select Widget

问题

我不确定是否有什么特殊的事情我应该做,但我有一个类似以下的模型和表单:

# models.py
from django.db import models

class ObjectModel(models.Model):
    object = models.DecimalField(max_digits=10, decimal_places=2)
# my_settings.py
from decimal import Decimal

object_choices = [
    (Decimal('1'),'1'),
    (Decimal('1.5'),'1.5'),
    (Decimal('2'),'2'),
    (Decimal('2.5'),'2.5'),
    (Decimal('3'),'2.5'),
]
# forms.py
from django import forms
from my_settings import object_choices
from models import ObjectModel

class ObjectForm(forms.ModelForm):
    object = forms.ChoiceField(choices=object_choices)
    class Meta:
        model = ObjectModel
        fields = ['object']

表单渲染正常,并且可以保存对象而没有任何问题。我可以在Django管理界面中看到我在表单上选择的值已保存到模型中,而且所有其他字段(未在上面显示)都能正常渲染和工作。

当我加载一个表单来编辑模型而不是创建一个新模型时,例如:

views.py
from forms import ObjectForm
...
form = ObjectForm(instance=obj)
...

渲染的选择小部件没有初始值。如果我删除表单定义中的'object'字段定义,让它使用默认文本输入渲染,一切都按预期工作,我可以看到正确的值,与我在Django管理中看到的值相同。

我已经检查过我正在将选择定义为Decimal对象,我尝试过将其更改为TypedChoiceField,还尝试在表单_init_中设置字段的初始值,但没有成功。

我还尝试将表单字段定义为带有选择小部件的DecimalField,例如:

# forms.py
... 
object = forms.DecimalField(
    widget=forms.Select(
        choices=object_choices,
    )
)

我不确定是否DecimalField和ChoiceField或Select小部件之间存在根本不兼容性,或者是否应该做一些特殊的事情。我已经搜索过其他问题,但没有看到任何内容可以表明为什么我所做的不起作用,因此任何帮助将不胜感激。

谢谢。

英文:

I'm not sure if there is something special I should be doing but I have a model and form similar to the following;

# models.py
from django.db import models

class ObjectModel(models.Model):
    object = models.DecimalField(max_digits=10, decimal_places=2)
# my_settings.py
from decimal import Decimal 

object_choices = [
    (Decimal('1'),'1'),
    (Decimal('1.5'),'1.5'),
    (Decimal('2'),'2'),
    (Decimal('2.5'),'2.5'),
    (Decimal('3'),'2.5'),
]
# forms.py
from django import forms
from my_settings import object_choices
from models import ObjectModel

class ObjectForm(forms.ModelForm):
    object = forms.ChoiceField(choices = object_choices)
    class Meta:
        model = ObjectModel
        fields = ['object']

The form renders fine, and saves the object without any problem. I can see in the Django Admin that the value I select on the form gets saved to the model, and all the other fields (not shown above) render and work fine.

When I load a form to edit the model rather than create a new one, e.g

views.py
from forms import ObjectForm
...
form = ObjectForm(instance = obj)
...

The select widget which renders doesn't have an initial value. If I delete the definition for 'object' in the form definition and let it render with the default text input, everything works as expected and I can see the correct value, the same as I can see in the Django admin.

I have checked that I am defining the choices as Decimal objects, I've tried to change to a TypedChoiceField and I have tried to set the fields initial value in the form init but without any luck.

I've also tried to define the form field as a DecimalField with a Select widget, e.g:

#forms.py 
... 
object = forms.DecimalField(
    widget=forms.Select(
        choices = object_choices,
    )
)

I'm not sure if there is a fundamental incompatibility between DecimalField and ChoiceField or the Select widget, or if there is maybe something special I should be doing. I've searched other questions but there's nothing I can see which would suggest why what I am doing wouldnt work so any help would be appreciated.

Thanks.

答案1

得分: 0

我认为我已经找到了问题,所以我在这里发布以便其他人能看到,如果有人遇到与我一样的问题,我在发布之前已经寻找了很长时间。

这里的问题似乎与小数字段如何解释和存储格式中规定的值有关,即使以不同方式输入,但在选择部件在选择初始值的选项时无法以相似的方式操作。

例如,我的模型将对象定义为:

object = models.DecimalField(max_digits=10, decimal_places=2)

我认为这意味着它存储了2位小数,而不管输入是什么。例如,Decimal('3')的输入将被存储为Decimal('3.00')。

从数字的角度来看,这些被认为是相等的,但从字符串的角度来看,它们并不相等,例如:

>>> from decimal import Decimal
>>> a = Decimal('3')
>>> b = Decimal('3.0')
>>> a == b
True
>>> str(a)== str(b)
False

因此,由于这个原因,我的选择列表是该字段的有效输入,但从我所了解的情况来看,它们都不匹配存储的值,因此初始值无法映射到其中一个选项。

我已经按照以下方式更改了我的选择,现在我可以正常使用ChoiceField和Select部件。

my_settings.py

from decimal import Decimal

object_choices = [
(Decimal('1.00'),'1'),
(Decimal('1.50'),'1.5'),
(Decimal('2.00'),'2'),
(Decimal('2.50'),'2.5'),
(Decimal('3.00'),'2.5'),
]

我不确定的是,如果现在,在创建模型并填充数据库的一些值之后,我想要更改模型以存储3位小数,那么之前保存的对象是否仍将具有2位小数,因此我的列表将不再起作用,还是它们都将被“升级”为3位小数。

英文:

I think I have found the problem and so am posting here for visibility should anyone else have the same issue as I looked for a long time before posting.

The problem here seems to be related to how the decimal field interprets and stores values to the format stipulated in the model, even which entered differently, but not being able to operate similarly backwards when the Select widget is looking for a match in the choices for an initial value.

For example, my model had the object defined as;

object = models.DecimalField(max_digits=10, decimal_places=2)

I think this means that it is stored with 2 decimal places, reguaradless of what is entered. E.g an entry of Decimal('3') would be stored as Decimal('3.00').

When compared as numbers these are considered equal, but when compared as strings they are not, for example;

>>> from decimal import Decimal
>>> a = Decimal('3')
>>> b = Decimal('3.0')
>>> a == b
True
>>> str(a) == str(b)
False

Because of this, my choices list were valid inputs for the field, but, from what I can tell, none of them matched the stored value, and so the initial value was unable to be mapped to one of the choices.

I have changed my choices as follows and now I can use the ChoiceField and Select widget OK.

# my_settings.py
from decimal import Decimal 

object_choices = [
    (Decimal('1.00'),'1'),
    (Decimal('1.50'),'1.5'),
    (Decimal('2.00'),'2'),
    (Decimal('2.50'),'2.5'),
    (Decimal('3.00'),'2.5'),
]

What I am not sure about is what would happen if now, after creating the model and populating the database with some values, I then wanted to change the model to store 3 decimal places. I dont know if objects previously saved would still have 2 decimal places and therefore my list would no longer work, or if they would all be "upgraded" to 3 decimal places.

huangapple
  • 本文由 发表于 2023年3月7日 06:54:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定