在 Django 模型表单中使用模型属性
•浏览 1
Use Model Property in a Django Model Form
我正在尝试在模型表单中使用模型属性,例如字段,但到目前为止还没有任何运气。结果是表单只呈现模型字段,而不是我定义的属性。知道如何让表单识别添加到模型中的属性吗?我希望看到纬度属性作为表单中的另一个字段添加。
模型.py:
class Plot(models.Model):
plot_id = models.AutoField(primary_key=True)
plot_number = models.IntegerField(validators=[MinValueValidator(1)], null=False, unique=True)
geometry = models.PointField(srid=2163, null=True, blank=True)
objects = models.GeoManager()
@property
def latitude(self):
self.geometry.transform(4326)
return self.geometry.y
@latitude.setter
def latitude(self, latitude):
self.geometry.y = latitude
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = ("geometry", )
latitude = forms.WhateverField()
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
if instance:
kwargs['initial'] = {'latitude': instance.latitude, }
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.latitude = self.cleaned_data['latitude']
return super().save(*args, **kwargs)
class InventoryPlotForm(ModelForm):
latitude = forms.CharField(max_length=52) # Something like this
def save(self, commit=True):
model_instance = super(InventoryPlotForm, self).save(commit=False)
result = super(InventoryPlotForm, self).save(commit=True)
model_instance.latitude = self.cleaned_data['latitude']
model_instance.save()
return result
class Meta:
model = ForestInventoryPlot
widgets = {'geometry': HiddenInput()}
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...
Forms.py:
class Plot(models.Model):
plot_id = models.AutoField(primary_key=True)
plot_number = models.IntegerField(validators=[MinValueValidator(1)], null=False, unique=True)
geometry = models.PointField(srid=2163, null=True, blank=True)
objects = models.GeoManager()
@property
def latitude(self):
self.geometry.transform(4326)
return self.geometry.y
@latitude.setter
def latitude(self, latitude):
self.geometry.y = latitude
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = ("geometry", )
latitude = forms.WhateverField()
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
if instance:
kwargs['initial'] = {'latitude': instance.latitude, }
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.latitude = self.cleaned_data['latitude']
return super().save(*args, **kwargs)
class InventoryPlotForm(ModelForm):
latitude = forms.CharField(max_length=52) # Something like this
def save(self, commit=True):
model_instance = super(InventoryPlotForm, self).save(commit=False)
result = super(InventoryPlotForm, self).save(commit=True)
model_instance.latitude = self.cleaned_data['latitude']
model_instance.save()
return result
class Meta:
model = ForestInventoryPlot
widgets = {'geometry': HiddenInput()}
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...
若干年后。一个完整的答案,在 Django 中工作到 2.2。正如其他人指出的那样,模型表单中只包含真正的数据库字段。因此,您需要:
- 定义自定义模型表单,添加您的 @property 字段
- 排除您的几何字段
- 在表单的 __init__ 中,获取值,并将其设置为 initial。
- 自定义您的保存方法(在表单或管理员上)
注意:这也适用于更复杂的情况,您想抽象出一些更复杂的数据库结构...
class Plot(models.Model):
plot_id = models.AutoField(primary_key=True)
plot_number = models.IntegerField(validators=[MinValueValidator(1)], null=False, unique=True)
geometry = models.PointField(srid=2163, null=True, blank=True)
objects = models.GeoManager()
@property
def latitude(self):
self.geometry.transform(4326)
return self.geometry.y
@latitude.setter
def latitude(self, latitude):
self.geometry.y = latitude
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = ("geometry", )
latitude = forms.WhateverField()
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
if instance:
kwargs['initial'] = {'latitude': instance.latitude, }
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.latitude = self.cleaned_data['latitude']
return super().save(*args, **kwargs)
class InventoryPlotForm(ModelForm):
latitude = forms.CharField(max_length=52) # Something like this
def save(self, commit=True):
model_instance = super(InventoryPlotForm, self).save(commit=False)
result = super(InventoryPlotForm, self).save(commit=True)
model_instance.latitude = self.cleaned_data['latitude']
model_instance.save()
return result
class Meta:
model = ForestInventoryPlot
widgets = {'geometry': HiddenInput()}
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...
ModelForm 仅自动生成 Django 字段。
- 您需要在 ModelForm 中定义您的字段
- 可能使几何场隐藏
- 编写自定义 ModelForm Save 方法,分别保存模型字段和模型属性。
- 修改视图以设置 ModelForm 的初始值
例如这样的:
class Plot(models.Model):
plot_id = models.AutoField(primary_key=True)
plot_number = models.IntegerField(validators=[MinValueValidator(1)], null=False, unique=True)
geometry = models.PointField(srid=2163, null=True, blank=True)
objects = models.GeoManager()
@property
def latitude(self):
self.geometry.transform(4326)
return self.geometry.y
@latitude.setter
def latitude(self, latitude):
self.geometry.y = latitude
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = ("geometry", )
latitude = forms.WhateverField()
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
if instance:
kwargs['initial'] = {'latitude': instance.latitude, }
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.latitude = self.cleaned_data['latitude']
return super().save(*args, **kwargs)
class InventoryPlotForm(ModelForm):
latitude = forms.CharField(max_length=52) # Something like this
def save(self, commit=True):
model_instance = super(InventoryPlotForm, self).save(commit=False)
result = super(InventoryPlotForm, self).save(commit=True)
model_instance.latitude = self.cleaned_data['latitude']
model_instance.save()
return result
class Meta:
model = ForestInventoryPlot
widgets = {'geometry': HiddenInput()}
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...
在你看来
class Plot(models.Model):
plot_id = models.AutoField(primary_key=True)
plot_number = models.IntegerField(validators=[MinValueValidator(1)], null=False, unique=True)
geometry = models.PointField(srid=2163, null=True, blank=True)
objects = models.GeoManager()
@property
def latitude(self):
self.geometry.transform(4326)
return self.geometry.y
@latitude.setter
def latitude(self, latitude):
self.geometry.y = latitude
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = ("geometry", )
latitude = forms.WhateverField()
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
if instance:
kwargs['initial'] = {'latitude': instance.latitude, }
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.latitude = self.cleaned_data['latitude']
return super().save(*args, **kwargs)
class InventoryPlotForm(ModelForm):
latitude = forms.CharField(max_length=52) # Something like this
def save(self, commit=True):
model_instance = super(InventoryPlotForm, self).save(commit=False)
result = super(InventoryPlotForm, self).save(commit=True)
model_instance.latitude = self.cleaned_data['latitude']
model_instance.save()
return result
class Meta:
model = ForestInventoryPlot
widgets = {'geometry': HiddenInput()}
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...
您的属性不是 Field 实例,因此 ModelForm 无法自动为其生成表单字段。您需要在 InventoryPlotForm 上显式定义一个 latitude 字段,并在表单的 __init__ 和 save 方法中管理其检索和更新。或者,您可以实现自己的 Widget 类并告诉您的 InventoryPlotForm 将其用于 geometry 字段:
class Plot(models.Model):
plot_id = models.AutoField(primary_key=True)
plot_number = models.IntegerField(validators=[MinValueValidator(1)], null=False, unique=True)
geometry = models.PointField(srid=2163, null=True, blank=True)
objects = models.GeoManager()
@property
def latitude(self):
self.geometry.transform(4326)
return self.geometry.y
@latitude.setter
def latitude(self, latitude):
self.geometry.y = latitude
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = ("geometry", )
latitude = forms.WhateverField()
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
if instance:
kwargs['initial'] = {'latitude': instance.latitude, }
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.latitude = self.cleaned_data['latitude']
return super().save(*args, **kwargs)
class InventoryPlotForm(ModelForm):
latitude = forms.CharField(max_length=52) # Something like this
def save(self, commit=True):
model_instance = super(InventoryPlotForm, self).save(commit=False)
result = super(InventoryPlotForm, self).save(commit=True)
model_instance.latitude = self.cleaned_data['latitude']
model_instance.save()
return result
class Meta:
model = ForestInventoryPlot
widgets = {'geometry': HiddenInput()}
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...