Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Geodjango admin, display pointfield not as map

This may be a stupid question but I can't find any clear answers.

How do I change the display in the Django Admin so the Pointfield does not show up like a OpenLayer Map but as a regular input field. I need to see the long, lat for debugging..

Do i have to change the field type? Widgets?

Thanks!

like image 814
user3199840 Avatar asked Jan 28 '14 14:01

user3199840


2 Answers

Update

This is how I managed -at last- to keep separate fields for lattitude and longitude without having to save them in the database since the values are already saved in the PointField.

The idea is :

  • If we are inserting a new entry, the latitude and longitude fields will be used to set the PointField
  • If we open an existing PointField entry, it will be used to provide the latitude and longitude values in the relevant FormFields.

models.py

from django.contrib.gis.db import models as geomodels


class Entry(geomodels.Model):
    point = geomodels.PointField(
        srid=4326,
        blank=True,
        )

admin.py

from myapp.forms import EntryForm
from django.contrib import admin


class EntryAdmin(admin.ModelAdmin):
    form = EntryForm


admin.site.register(Entry, EntryAdmin)

forms.py

from django import forms
from myapp.models import Entry
from django.contrib.gis.geos import Point


class MarketEntryForm(forms.ModelForm):

    latitude = forms.FloatField(
        min_value=-90,
        max_value=90,
        required=True,
    )
    longitude = forms.FloatField(
        min_value=-180,
        max_value=180,
        required=True,
    )

    class Meta(object):
        model = MarketEntry
        exclude = []
        widgets = {'point': forms.HiddenInput()}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        coordinates = self.initial.get('point', None)
        if isinstance(coordinates, Point):
            self.initial['longitude'], self.initial['latitude'] = coordinates.tuple

    def clean(self):
        data = super().clean()
        latitude = data.get('latitude')
        longitude = data.get('longitude')
        point = data.get('point')
        if latitude and longitude and not point:
            data['point'] = Point(longitude, latitude)
        return data

From the source code of PointField we see that its form class uses the OpenLayersWidget which inherits from the BaseGeometryWidget.

The conclusion is that in this class, the variable display_raw is by default set to False.

If you set it to True in yourapp/admin.py, you will get a textbox with lat and long and other data, useful for debugging purposes:

from django.contrib.gis import admin
from yourapp.models import YourClass
from django.contrib.gis import forms
from django.contrib.gis.db import models    


class YourClassAdminForm(forms.ModelForm):
    your_attribute = forms.PointField(widget=forms.OSMWidget(attrs={
            'display_raw': True}))

class YourClassAdmin(admin.GeoModelAdmin):
    form = YourClassAdminForm


admin.site.register(YourClass, YourClassAdmin)

There is also a way to have both a map and manual insertion of longitude / latitude permanently (not only for debugging).

The idea is to use FloatFields to insert the Longitude/Latitude and update the PointField with the inserted data.

like image 177
raratiru Avatar answered Nov 14 '22 16:11

raratiru


You can override a widget with another in Django admin. From the documentation -

from django.db import models
from django.contrib import admin

# Import our custom widget and our model from where they're defined
from myapp.widgets import RichTextEditorWidget
from myapp.models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': RichTextEditorWidget},
    }

This overrides TextField with RichTextEditorWidget. Just find the field type for point field and override it with TextField.

like image 27
Bibhas Debnath Avatar answered Nov 14 '22 15:11

Bibhas Debnath