Django在渲染ModelForm之前改变模型数据

时间:2016-12-07 18:20:59

标签: python django

我正在尝试生成一个对象,该对象允许将值存储在标准单元中,但根据项目的设置以不同的单位显示。以下是我需要能够存储房间温度的示例。我希望数据库值以开尔文为单位,以便于计算,但希望用户能够根据项目需要查看/输入F或C.

模型可以从表单中获取值,并在保存时将它们转换为开尔文。我知道这可以在表单中完成,但我在这里有其他数据输入方法。该模型的条纹版本如下:

class Room(models.Model):
    name                = models.CharField(max_length=255)            
    temperature         = models.FloatField(default=293.15)

    def save(self, *args, **kwargs):
        self.temperature = convert.temperature(self.temperature, 
            from_unit=self.plant.temperature_scale)
        super(Room, self).save(*args, **kwargs)

我创建了一个在CreateView和UpdateView中使用的ModelForm。我需要ModelForm来限制其他字段的查询集(工作正常)。在这里,我能够将温度字段转换为CreateView中新对象的所需单位,但我似乎找不到为现有记录拉出这个的方法

class RoomForm(ModelForm):
    def __init__(self, plant, *args, **kwargs):
        super (RoomForm,self ).__init__(*args,**kwargs)

        self.fields['temperature'].initial = convert.temperature(
            value=self.fields['temperature'].initial, 
            from_unit='K',
            to_unit=self.fields['unit'].queryset[0].plant.temperature_scale)

        self.instance.temperature = convert.temperature(
            value=self.instance.temperature, 
            from_unit='K',
            to_unit=self.fields['unit'].queryset[0].plant.temperature_scale)

    class Meta:
        model = Room
        fields = ['name', 'temperature']

为了更好地衡量,以下是调用此表单的视图。

class NewRoom(CreateView):
    model = Room
    form_class = RoomForm

    def get_form_kwargs(self, **kwargs):
        form_kwargs = super(NewRoom, self).get_form_kwargs(**kwargs)
        form_kwargs["plant"] = Plant.objects.get(slug=self.kwargs['plant'])
        return form_kwargs    

class EditRoom(UpdateView):
    model = Room
    form_class = RoomForm
    template_name_suffix = "_update_form"

    def get_form_kwargs(self, **kwargs):
        form_kwargs = super(EditRoom, self).get_form_kwargs(**kwargs)
        form_kwargs["plant"] = Plant.objects.filter(slug=self.kwargs['plant'])
        return form_kwargs

在模板(非表格)中,我用它来正确显示温度。

{{ room.temperature|convert_temperature:room.plant.temperature_scale }}

我假设我需要补充ModelForm从数据库记录中导入数据的部分,但我无法确定django.forms源代码中发生这种情况的位置。

我尝试在shell中手动调用

>>> from rooms.models import *
>>> from rooms.forms import *
>>> room = Room.objects.first()
>>> form = RoomForm(room.plant, instance=room)
>>> form.instance.temperature
20.0 
>>> form.as_p()

,渲染形式如下,温度值

不正确
<p>
    <label for="id_name">Name:
    </label> 
    <input id="id_name" maxlength="255" name="name" type="text" value="Testing" 
        required />
</p>\n
<p>
    <label for="id_temperature">Temperature:
    </label> 
    <input id="id_temperature" name="temperature" 
        step="any" type="number" value="293.15" required /> 
</p>\n

我正在使用Django版本1.10.3,如果这可能是一个错误。

2 个答案:

答案 0 :(得分:1)

要在呈现之前修改现有记录中的数据,只需在调用父self.instance之后在__init__中执行此操作。

def __init__(self, plant, *args, **kwargs):
    super(RoomForm,self ).__init__(*args,**kwargs)
    self.instance.temperature = # ...

答案 1 :(得分:1)

虽然lucasnadalutti让我在正确的位置,但它没有设法做到这一点。覆盖传递给ModelForm.__init__的实例并在更改后再次调用它。

class RoomForm(ModelForm):

    def __init__(self, plant, *args, **kwargs):
        super(RoomForm, self).__init__(*args,**kwargs)

        self.instance.temperature = convert.temperature(
            value=self.instance.temperature,
            from_unit='K', to_unit=self.fields['unit'].queryset[0].plant.temperature_scale)

        # Override instance passed to __init__ and call super again
        kwargs['instance'] = self.instance
        super(RoomForm, self).__init__(*args, **kwargs)

    class Meta:
        model = Room
        fields = ['name', 'temperature']