Pergunta

In my django application I have a map displayed when I'm in the admin thanks to the class OSMGeoAdmin (from django.contrib.gis.admin) the only problem is that this map kind of reverse the GPS coordinates (lat, long).

Example : Point(48, 2) should point near Orléans (in France) instead of that the map points to (2, 48) which is near Somalia.

It is not problematic for the server, but it is when I want to check those coordinates.

Could anyone help me with this issue please ?

Foi útil?

Solução 2

Solved this problem with a simple tweak. Redefining the render method is far more simple and doesn't imply database/model modification. For example :

def get_map_widget(self, db_field):
    mapped = super(MissionAdmin, self).get_map_widget(db_field)

    def render(inner_self, name, value, attrs=None):
        if value and isinstance(value, Point):
            value.x, value.y = value.y, value.x
        return super(mapped, inner_self).render(name, value, attrs)

    mapped.render = render
    return mapped

That implies when the map is being rendered, just before generating the HTML (rendering process) I just reverse the points when displaying them. Of course it's kind of dangerous if, for example, it's not a readonly map. In this case you have to modify the save_model method to reverse again your coordinates.

Outras dicas

If your coordinates in your db are the wrong way around you should fix that. In ./manage.py shell:

from app.models import Point

for obj in Point.objects.all():
    obj.lat, obj.lng = obj.lng, obj.lat
    obj.save()

Now you only have to fix your 'kind of reverse' problem. The reason why the coordinates are stored to the wrong way around in the first place.

EDIT

If you only want to return a coordinate the other way around you can define a custom method on a model to add custom “row-level” functionality to your objects. See: Model methods.

def _get_reversed_point(self):
    "Returns the reversed point (lng, lat)."
    return (self.point.lng, self.point.lat)
reversed_point = property(get_reversed_point)

Now you can query your db normally and when dealing with reversed points use obj.reversed_point which will return the reversed tuple.

EDIT 2

The reversed_point isn't part of the form and therefore can't be used in the change view unless you add it yourself. This is done by ModelAdmin.form. In the form you can (re)define a field and specify a widget. Create a widget by overridinging an excising widget. It goes like this:

from somewhere import SomeWidget

class MyWidget(SomeWidget):
    def render(self, name, value, attrs=None):
        output = []
        template = '<p>Your html that will display a beautiful map. Point: %(lat)s %(lng)s</p>'
        output.append(template % {'lat':self.instance.point.lat, 'lng':self.instance.point.lng, })
        output.append(super(SomeWidget, self).render(name, value, attrs))
        return mark_safe(u''.join(output))


class MyForm(forms.ModelForm):
    point = forms.SomeField(widget=MyWidget)

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

        if hasattr(self, 'instance'):
            # This gives the widget access to all fields in MyModel object.
            self.fields['point'].widget.instance = self.instance

    class Meta:
        model = MyModel
        exclude = []

class MyAdmin(admin.ModelAdmin):
    form = MyForm

GeoDjango comes with some widgets. Reading their code is a good starting point and will learn you where the widgets apply the point info the 'wrong' way around. Good luck.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top