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): = 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.long, value.addr)

    def to_python(self, value):
        if isinstance(value, LatLong):
            return value

            x = value.split(',')
            return LatLong(lat=0,long=0,addr='')

        return LatLong(lat=x[0], long=x[1], addr=','.join(x[2:]))


And my

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 = { 
        js = ( 

    def __init__(self, attrs=None):
        default_attrs = {}

        if 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',
                                     '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)


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

1 answer

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.long, value.addr), attrs)

    output += render_to_string('maps/coord.html',
                                 'latlong': value,

    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.



All Articles