Django custom form field displays value incorrectly
I am trying to create a custom model field and widget to display google maps api v3 and click - select point and save that.
The value in the database must be in this format: LAT, LONG, FORMATTED_ADDRESS_BY_GOOGLE_REVERSE_GEOCODER
Here's my .py fields:
from django.db import models
class LatLong(object):
def __init__(self, *args, **kwargs):
self.lat = kwargs.get('lat',0)
self.long = kwargs.get('long',0)
self.addr = kwargs.get('addr','')
class CoordField(models.Field):
description = 'Coordinates field'
__metaclass__ = models.SubfieldBase
def __unicode__(self):
return 'LatLong obj'
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 255
super(CoordField, self).__init__(*args, **kwargs)
def db_type(self, connection):
return 'varchar(%s)' % self.max_length
def get_prep_value(self, value):
return '%s,%s,%s' % (value.lat, value.long, value.addr)
def to_python(self, value):
if isinstance(value, LatLong):
return value
try:
x = value.split(',')
except:
return LatLong(lat=0,long=0,addr='')
return LatLong(lat=x[0], long=x[1], addr=','.join(x[2:]))
And my widgets.py:
from django.forms import Widget, TextInput
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from settings import GMAPS_API_KEY
class LatLongWidget(TextInput):
class Media:
css = {
'all':('testing.css',)
}
js = (
'resource/js/coord.js',
)
def __init__(self, attrs=None):
default_attrs = {}
if attrs:
default_attrs.update(attrs)
super(LatLongWidget, self).__init__(default_attrs)
def render(self, *args, **kwargs):
output = super(LatLongWidget, self).render(*args, **kwargs)
output += render_to_string('maps/coord.html',
{'GMAPS_API_KEY':GMAPS_API_KEY,
'latlong': args[1]})
return mark_safe(output)
As I understand it, defining to_python () from a field should always return a python object, while get_prep_value () should do the exact opposite.
As you can see from the screenshot below, the result of the field in the form is not 3 comma separated values, but a string representation of the LatLong object returned by to_python ().
This happens automatically in my widget when I call output = super(LatLongWidget, self).render(*args, **kwargs)
Screenshot:
What am I missing here? Should I perform more functions? Did I do it completely wrong?
Any help would be greatly appreciated. Thank.
source to share
I changed the renderget () method for the widget to check the type of the passed value parameter and convert it to a LatLong object if needed:
def render(self, name, value, attrs=None):
if not isinstance(value, LatLong):
value = value.split(',')
value = LatLong(lat=value[0], long=value[1], addr=value[2:])
output = super(LatLongWidget, self).render(name, '%s,%s,%s' % (value.lat, value.long, value.addr), attrs)
output += render_to_string('maps/coord.html',
{'GMAPS_API_KEY':GMAPS_API_KEY,
'latlong': value,
'id':attrs['id'],})
return mark_safe(output)
It looks like I fixed my problem as the 'value' parameter passed to render () is either a unicode string (when the form is submitted) or a LatLong object when the form is rendered.
source to share