2011-08-27 107 views
4

我的模型中有一個模型的緯度和經度字段以浮點數的形式存儲在數據庫中。我喜歡這樣保持,因爲它可以讓我最有效地與他們合作。Django中的自定義緯度/經度表格字段

我希望用戶能夠以這種格式在股票管理界面中編輯它們:(+/-)DD MM SS.S(這是大多數GPS設備向最終用戶提供座標的方式)。

我想過的三種方式實現這一點:

  1. 使用GeoDjango內置 - 開銷太大,我根本就沒有需要完整的框架,只爲兩個字段。
  2. 定義自定義模型字段,somehow in this way。看起來像很多編碼,我不完全確定是否可以使用Django數據庫接口輕鬆訪問浮點表示。
  3. 使用MultiValueField和MultiWidget - 這不會是一個完全不好的解決方案,但是文檔記錄很差,並且還需要一些編碼和不必要的小部件,用於度,分和秒。

但理想情況下,我想這樣做:

  • 使用自定義形式場這將使用標準的TextInput表單控件和標準FloatField示範田。

我確定to_python()方法可以處理文本輸入並將其轉換爲float。但是,如何在編輯模型時告訴Django將float轉換爲我的經緯度表示?我該如何堅持下去呢?

回答

3

爲什麼不在模型中添加更多的字段來保存座標數據,然後讓模型的save()方法將這些數據轉換爲經度和緯度數字?然後在管理員中,只對lat/lon進行讀取,以便可以查看這些值,但不能進行編輯。或者,你可能決定不顯示它們!

例如:

class Location(models.Model): 

    latitude = ... 
    longitude = ... 

    lat_degrees = models.IntegerField() 
    lat_minutes = models.IntegerField() 
    lat_seconds = models.FloatField() 

    def save(self, *args, **kwargs): 
     # Do the maths here to calculate lat/lon 
     self.latitude = ... 
     self.longitude = ... 
     super(Location, self).save(*args, **kwargs) 

我假設你還需要lon_degrees領域,我猜,我在統籌方面的專家。我已經把這些留在了例子之外。您可能還想爲管理員創建一個新窗口小部件,以使其顯示得很好,或者僅覆蓋change_form.html以使這三個字段顯示在同一行上,但這稍微超出了此答案的範圍。

+0

這是一個簡單而且非常容易實現的解決方案,儘管不是太優雅。沒有想到它 - 謝謝! –

0

我最近有這個要求,並有一點點被帶走,但我想我會分享。 (Django 2.0。)

我創建了一個30個字符的CharField來包含座標,如輸入N 35º 44.265 W 41º 085.155(我不知道在哪裏,順便說一下......)並安排模型來存儲字段值。

import re 
from django.core.exceptions import ValidationError 

COORDINATES_REGEX = r'(?:[NS])\s*([0-9]{2})[\º\°]?\s+([0-9]{1,3}\.[0-9]{3})\s*(?:[EW])\s*([0-9]{2,3})[\º\°]?\s+([0-9]{2,3}\.[0-9]{3})' 

def decode_coords_string(str): 
    """ 
    Given a string, converts it to a decimal (lat, lng, 'OK', matched_string) tuple. 
    If invalid, returns "(None, None, <some reason>, None)." 

    Test for errors by checking that the coordinate is not 'None.' 

    'matched_string' returns the actual extent of the matched string regardless of where in the input-string it was, 
     for sanitizing the input when storing it in the database. (If the input string contains only blanks, we should 
     store an empty-string.) 
    The model will replace the field-value with this matched-string. 
    """ 
    # Dispose of empty input, returning an empty string(!) as the 'matched_string' in this case. 
    r = re.compile(r'^\s*$') 
    if r.match(str): 
     return (None, None, 'Empty string', '') 

    # Build the regex for coordinates. 
    r = re.compile(COORDINATES_REGEX, re.IGNORECASE) 

    # Try to match the string 
    p = r.match(str) 
    if p is None: 
     return (None, None, 'Syntax error', None) 

    # Get the pieces and expressly convert them to numeric types 
    (lat_degs, lat_mins, lng_degs, lng_mins) = p.groups() 

    lat_degs = int(lat_degs) 
    lat_mins = float(lat_mins) 
    lng_degs = int(lng_degs) 
    lng_mins = float(lng_mins) 

    # Throw out anything that simply does not make sense 
    if (lat_degs > 180) or (lng_degs > 180) or (lat_mins > 60.0) or (lng_mins > 60.0): 
     return (None, None, 'Degs/Mins value(s) out of bounds') 

    latitude = float(lat_degs) + (lat_mins/60.0) 
    longitude = (float(lng_degs) + (lng_mins/60.0)) * -1.0 

    return (latitude, longitude, 'OK', p.group()) 


def validate_coords(str): 
    """ 
    Simple validator for a coordinate string. 
    """ 
    (lat, lng, reason, str2) = decode_coords_string(str) 
    if lat is None: 
     raise ValidationError('Invalid coordinates: ' + reason) 

輸入CharField指定validators=[validate_coords]還要注意的是度符號可以指定多種方式或完全省去。

和模型包括以下短方法:

def save(self, *args, **kwargs): 
""" 
Calculate and automatically populate the numeric lat/long figures. 
This routine assumes that the string is either empty or that it has been validated. 
An empty string – or, for that matter, an invalid one – will be (None, None). 
""" 

(lat, lng, reason, cleaned) = decode_coords_string(self.coordinate_str) 

self.coordinate_str = cleaned 
self.latitude  = lat 
self.longitude  = lng 
super().save(*args, **kwargs) 

admin.py我排除latitudelongitude字段(這兩者都是浮動場)從視圖,爲了避免混淆用戶。數字字段會自動計算,但不會顯示。