I am attempting to use model properties like fields within a model form, but so far haven't had any luck. The result is that the form renders only the model fields, and not the property I defined. Any idea how to get the form to recognize the property added to the model? I expect to see the latitude property added as just another field in the form.
Models.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
Forms.py:
class InventoryPlotForm(ModelForm):
class Meta:
model = ForestInventoryPlot
exclude = {"geometry"}
str function in a django model returns a string that is exactly rendered as the display name of instances for that model.
Model: A model is the single, definitive source of data about your data. It contains the essential fields and behaviours of the data you're storing. Generally, each model maps to a single database table.
Models inheritance works the same way as normal Python class inheritance works, the only difference is, whether we want the parent models to have their own table in the database or not. When the parent model tables are not created as tables it just acts as a container for common fields and methods.
For this reason, Django provides a helper class that lets you create a Form class from a Django model. The generated Form class will have a form field for every model field specified, in the order specified in the fields attribute. Each model field has a corresponding default form field.
In Django, this isn’t usually permitted for model fields. If a non-abstract model base class has a field called author, you can’t create another model field or define an attribute called author in any class that inherits from that base class. This restriction doesn’t apply to model fields inherited from an abstract model.
Instead, when it is used as a base class for other models, its fields will be added to those of the child class. The Student model will have three fields: name, age and home_group. The CommonInfo model cannot be used as a normal Django model, since it is an abstract base class.
Django will prevent any attempt to save an incomplete model, so if the model does not allow the missing fields to be empty, and does not provide a default value for the missing fields, any attempt to save () a ModelForm with missing fields will fail.
Some years later. A complete answer, working in Django up to 2.2. As others have pointed out, only real db fields are included in the model form. So, you'll need to:
__init__
of the form, get the value, and set it as initial
.Note: This works also in more complex cases, where you want to abstract away some more complex database structure...
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)
Your property is not a Field
instance, and as such a ModelForm
cannot automatically generate a form field for it. You will need to explicitly define a latitude
field on the InventoryPlotForm
and manage its retrieval and update in the form's __init__
and save
methods. Alternatively, you can implement your own Widget
class and tell your InventoryPlotForm
to use it for the geometry
field:
class InventoryPlotForm(ModelForm):
class Meta(object):
widgets = {
'geometry': MyGeometryWidget,
}
...
...
Only Django Fields are automatically generated by ModelForm.
For example something like this:
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()}
in your view
...
form = InventoryPlotForm(instance=forestinventoryplot,
initial={"latitude":forestinventoryplot.latitude})
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With