2013-06-10 5 views

Antwort

6

Hier ist mein Arbeits benutzerdefiniertes Feld und widget:

class LatLongWidget(forms.MultiWidget): 
    """ 
    A Widget that splits Point input into two latitude/longitude boxes. 
    """ 

    def __init__(self, attrs=None, date_format=None, time_format=None): 
     widgets = (forms.TextInput(attrs=attrs), 
        forms.TextInput(attrs=attrs)) 
     super(LatLongWidget, self).__init__(widgets, attrs) 

    def decompress(self, value): 
     if value: 
      return tuple(reversed(value.coords)) 
     return (None, None) 

class LatLongField(forms.MultiValueField): 

    widget = LatLongWidget 
    srid = 4326 

    default_error_messages = { 
     'invalid_latitude' : _('Enter a valid latitude.'), 
     'invalid_longitude' : _('Enter a valid longitude.'), 
    } 

    def __init__(self, *args, **kwargs): 
     fields = (forms.FloatField(min_value=-90, max_value=90), 
        forms.FloatField(min_value=-180, max_value=180)) 
     super(LatLongField, self).__init__(fields, *args, **kwargs) 

    def compress(self, data_list): 
     if data_list: 
      # Raise a validation error if latitude or longitude is empty 
      # (possible if LatLongField has required=False). 
      if data_list[0] in validators.EMPTY_VALUES: 
       raise forms.ValidationError(self.error_messages['invalid_latitude']) 
      if data_list[1] in validators.EMPTY_VALUES: 
       raise forms.ValidationError(self.error_messages['invalid_longitude']) 
      # SRID=4326;POINT(1.12345789 1.123456789) 
      srid_str = 'SRID=%d'%self.srid 
      point_str = 'POINT(%f %f)'%tuple(reversed(data_list)) 
      return ';'.join([srid_str, point_str]) 
     return None 
+1

Ich erhalte eine ‚ungültige Geometriewert‘ Fehler, wenn ich diese – fangsterr

+0

verwenden @fangsterr Sie verwenden '' 'FloatField''' oder' '' DecimalField''' Ihre Koordinaten und Überschreibung zu speichern die Speichermethode zum Aktualisieren des '' 'PointField''', wie hier [hier] (http://stackoverflow.com/a/22309195/2996101) – raratiru

0

Erstellen Sie ein benutzerdefiniertes Widget für diese, können Sie sich von SelectDateWidgethere inspirieren lassen.

3

@Ramast, nähern sich das gleiche Problem in einer pythonic Weise. Ich habe die Änderungen in meinen Code aufgenommen, es fühlt sich toll an, immer besser zu werden.


Dies ist, wie ich es geschafft, -bei letzt lattitude und Länge getrennte Felder zu halten, ohne sie in der Datenbank zu speichern, die, da die Werte bereits im PointField gespeichert werden.

Die Idee ist:

  • Wenn wir einen neuen Eintrag einfügen, die Breiten- und Längenfelder verwendet werden, um die PointField
  • einstellen Wenn wir einen vorhandenen PointField Eintrag öffnen, wird es verwendet werden Geben Sie die Breiten- und Längengradwerte in den entsprechenden FormFields an.

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['latitude'], self.initial['longitude'] = 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 
3

Dieses basiert auf @ rara_tiru-Lösung, aber mit einigen Verbesserungen

class GisForm(forms.ModelForm): 
    """ 
    This form can be used by any model that has "coordinates" field. 
    It will show a better looking map than the default one 
    """ 
    lat = forms.FloatField(required=False) 
    lng = forms.FloatField(required=False) 
    coordinates = PointField(widget=CustomPointWidget(), required=False, srid=4326) 

    def __init__(self, *args, **kwargs): 
     super(GisForm, self).__init__(*args, **kwargs) 
     coordinates = self.initial.get("coordinates", None) 
     if isinstance(coordinates, Point): 
      self.initial["lng"], self.initial["lat"] = coordinates.tuple 

    def clean(self): 
     data = super(GisForm, self).clean() 
     if "lat" in self.changed_data or "lng" in self.changed_data: 
      lat, lng = data.pop("lat", None), data.pop("lng", None) 
      data["coordinates"] = Point(lng, lat, srid=4326) 

     if not (data.get("coordinates") or data.get("lat")): 
      raise forms.ValidationError({"coordinates": "Coordinates is required"}) 
     return data 

Damit können Benutzer entweder den Standort auf der Karte festlegen oder die Werte für lat/lng manuell eingeben. einmal gespeichert wird die Karte die specificed lat/lng Wert

1

Die Antworten sind für den Aufbau Ihrer eigenen Lösung widerspiegeln, aber wenn Sie eine einfache Lösung wollen, die gut aussieht und ist einfach zu bedienen, versuchen: http://django-map-widgets.readthedocs.io/en/latest/index.html

Sie können:

  • geben Sie die Koordinaten
  • Navigation direkt auf der Karte
  • Artikel nachschlagen von Google Orten.

Screen Shot from Django Map Widgets

Verwandte Themen