Custom Latitude / Longitude Shape Field in Django

One of my models has latitude and longitude fields that are stored in the database as floating point numbers. I like to keep it that way because it allows me to work with them most efficiently.

I would like users to be able to edit them in the inventory management interface in this format: (+/-) DD MM SS.S (the way most GPS devices provide coordinates to the end user).

I thought of three ways to implement this:

  • Using GeoDjango is too much overhead, I just don't need a complete structure for just two fields.
  • Define your own model this way . There seems to be a lot of coding, and I'm not quite sure if I can easily access the floating point view using the Django database interface.
  • Using MultiValueField and MultiWidget is not a bad solution, but it is poorly documented and also requires a little coding and unnecessary widgets for degrees, minutes and seconds.

But ideally, I would like to do this:

  • Use the custom form field, which will use the standard TextInput form widget and the standard FloatField model field.

I am sure that the to_python () method can handle text input and convert it to float. But how do I tell Django to convert the float to my lat / lng view when editing the model? And how do I put it all together?

+4
source share
2 answers

Why not add a few more fields to your model to store coordinate data, and then the save() method of your model converts them to latitude and longitude values? Then in the administrator, do lat / lon read-only so that the values ​​can be viewed, but not edited. Or you may not show them at all!

For instance:

 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) 

I assume that you will also need lon_degrees fields, I assume that I am not a specialist in coordinates. I left them in this example. You can also create a new widget for the administrator so that it displays well, or simply override change_form.html so that the three fields appear on the same line, but this is a bit beyond the scope of this answer.

+3
source

I recently received this requirement and got a little carried away, but I thought I would share it. (Django 2.0.)

I created a 30-character CharField to contain the coordinates entered, for example. N 35ΒΊ 44.265 W 41ΒΊ 085.155 (I have no idea where it is, by the way ...) and arranged for the Model to save the field values.

 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 input indicates validators=[validate_coords] Note that degrees can be specified in several ways or omitted altogether.

And the model includes the following short method:

 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) 

In admin.py I exclude the latitude and longitude fields (both of which are Float fields) from the view to avoid confusion with the user. Numeric fields are automatically calculated but not displayed.

0
source

Source: https://habr.com/ru/post/1369321/


All Articles