首页 文章

Django中的自定义纬度/经度表单字段

提问于
浏览
4

我的一个模型具有纬度和经度字段,它们作为浮点数存储在数据库中 . 我喜欢这样保留它,因为它允许我最有效地使用它们 .

我希望用户能够以这种格式在股票管理界面中编辑它们:( / - )DD MM SS.S(这就是大多数GPS设备向最终用户呈现坐标的方式) .

我想到了实现这个的三种方法:

  • 使用GeoDjango - 开销太大,我根本不需要只有两个字段的完整框架 .

  • 定义自定义 model 字段,somehow in this way . 看起来像很多编码,我不能完全确定我是否能够使用Django数据库接口轻松访问浮点表示 .

  • 使用MultiValueField和MultiWidget - 这不是一个完全糟糕的解决方案,但是文档记录很差,还包括一些编码和不必要的小部件,分钟和秒 .

但理想情况下,我想这样做:

  • 使用自定义 form 字段,该字段将使用标准TextInput表单窗口小部件和标准FloatField模型字段 .

我确信to_python()方法可以处理文本输入并将其转换为float . 但是在编辑模型时如何告诉Django将float转换为我的lat / lng表示?我该怎么把它们粘在一起?

2 回答

  • 3

    为什么不在模型中添加更多字段来保存坐标数据,然后让模型的 save() 方法将这些字段转换为纬度和经度数字?然后在admin中,使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

    我最近有这个要求并且有点被带走,但我想我会分享 . (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 字段(两者都是浮点字段),以避免混淆用户 . 数字字段会自动计算,但不会显示 .

相关问题