-
Notifications
You must be signed in to change notification settings - Fork 90
/
Copy pathgeo_fields.py
153 lines (124 loc) · 4.02 KB
/
geo_fields.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import json
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.geos.error import GEOSException
from django.utils.encoding import smart_str
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
EMPTY_VALUES = (None, '', [], (), {})
from django.contrib.gis.geos import Polygon
class PointField(serializers.Field):
"""
A field for handling GeoDjango Point fields as a json format.
Expected input format:
{
"latitude": 49.8782482189424,
"longitude": 24.452545489
}
"""
type_name = 'PointField'
type_label = 'point'
default_error_messages = {
'invalid': _('Enter a valid location.'),
}
def __init__(self, *args, **kwargs):
self.str_points = kwargs.pop('str_points', False)
self.srid = kwargs.pop('srid', None)
super(PointField, self).__init__(*args, **kwargs)
def to_internal_value(self, value):
"""
Parse json data and return a point object
"""
if value in EMPTY_VALUES and not self.required:
return None
if isinstance(value, str):
try:
value = value.replace("'", '"')
value = json.loads(value)
except ValueError:
self.fail('invalid')
if value and isinstance(value, dict):
try:
latitude = value.get("latitude")
longitude = value.get("longitude")
return GEOSGeometry('POINT(%(longitude)s %(latitude)s)' % {
"longitude": longitude,
"latitude": latitude},
srid=self.srid
)
except (GEOSException, ValueError):
self.fail('invalid')
self.fail('invalid')
def to_representation(self, value):
"""
Transform POINT object to json.
"""
if value is None:
return value
if isinstance(value, GEOSGeometry):
value = {
"latitude": value.y,
"longitude": value.x
}
if self.str_points:
value['longitude'] = smart_str(value.pop('longitude'))
value['latitude'] = smart_str(value.pop('latitude'))
return value
class PolygonField(serializers.Field):
"""
A field for handling GeoDjango PolyGone fields as a array format.
Expected input format:
{
[
[
51.778564453125,
35.59925232772949
],
[
50.1470947265625,
34.80929324176267
],
[
52.6080322265625,
34.492975402501536
],
[
51.778564453125,
35.59925232772949
]
]
}
"""
type_name = 'PolygonField'
type_label = 'polygon'
default_error_messages = {
'invalid': _('Enter a valid polygon.'),
}
def __init__(self, *args, **kwargs):
super(PolygonField, self).__init__(*args, **kwargs)
def to_internal_value(self, value):
"""
Parse array data and return a polygon object
"""
if value in EMPTY_VALUES and not self.required:
return None
try:
new_value = []
for item in value:
item = list(map(float, item))
new_value.append(item)
except ValueError:
self.fail('invalid')
try:
return Polygon(new_value)
except (GEOSException, ValueError, TypeError):
self.fail('invalid')
self.fail('invalid')
def to_representation(self, value):
"""
Transform Polygon object to array of arrays.
"""
if value is None:
return value
if isinstance(value, GEOSGeometry):
value = value.boundary.array
return value