2013-06-10 2 views

ответ

6

Вот мой рабочий настраиваемое поле и виджет:

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

Я получаю ошибку «недействительное значение геометрии», когда я использую этот – fangsterr

+0

@fangsterr Вы можете использовать '' 'FloatField''' или' '' DecimalField''' для хранения координат и переопределение метод сохранения для обновления '' 'PointField'', как показано на рисунке [здесь] (http://stackoverflow.com/a/22309195/2996101) – raratiru

0

Создайте новый виджет для этого продукта, и вы можете получить вдохновение от SelectDateWidgethere.

3

@Ramast, подходит один и тот же вопрос в более вещий образом. Я включил изменения в свой код, он чувствует себя прекрасно, чтобы всегда улучшаться.


Это, как мне удалось -при last- сохранить отдельные поля для Lattitude и долготы без необходимости сохранять их в базе данных, так как значения уже сохранены в PointField.

Идея такова:

  • Если мы вставляем новую запись, широта и долгота поле будет использоваться для установки PointField
  • Если открыть существующую запись PointField, она будет использоваться для обеспечить значения широты и долготы в соответствующих Формах.

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

Это основано на @ rara_tiru-х решение, но с некоторыми улучшениями

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 

Это позволит пользователям либо установить местоположение на карте, либо вручную поместить значения lat/lng. После сохранения карта будет отражать specificed LAT/LNG значение

1

Ответы отлично подходит для создания вашего собственного решения, но если вы хотите простое решение, которое хорошо выглядит и прост в использовании, попробуйте: http://django-map-widgets.readthedocs.io/en/latest/index.html

Вы можете:

  • введите координаты
  • выбрать непосредственно на карте
  • посмотреть предметы из мест Google.

Screen Shot from Django Map Widgets

Смежные вопросы