diff --git a/docs/changelog.rst b/docs/changelog.rst index 6820368c..427d2106 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,7 +4,8 @@ Changelog Changes in 0.8.5 ================ -- Fix testing invalid dict field value (#485) +- Fix setting Geo Location fields (#488) +- Fix handling invalid dict field value (#485) - Added app_label to MongoUser (#484) - Use defaults when host and port are passed as None (#483) - Fixed distinct casting issue with ListField of EmbeddedDocuments (#470) diff --git a/mongoengine/common.py b/mongoengine/common.py index 6303231e..daa194b9 100644 --- a/mongoengine/common.py +++ b/mongoengine/common.py @@ -25,7 +25,7 @@ def _import_class(cls_name): 'GenericEmbeddedDocumentField', 'GeoPointField', 'PointField', 'LineStringField', 'ListField', 'PolygonField', 'ReferenceField', 'StringField', - 'ComplexBaseField') + 'ComplexBaseField', 'GeoJsonBaseField') queryset_classes = ('OperationError',) deref_classes = ('DeReference',) diff --git a/mongoengine/fields.py b/mongoengine/fields.py index 036a00c2..2a270cc6 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -42,7 +42,8 @@ __all__ = ['StringField', 'URLField', 'EmailField', 'IntField', 'LongField', 'GenericReferenceField', 'BinaryField', 'GridFSError', 'GridFSProxy', 'FileField', 'ImageGridFsProxy', 'ImproperlyConfigured', 'ImageField', 'GeoPointField', 'PointField', - 'LineStringField', 'PolygonField', 'SequenceField', 'UUIDField'] + 'LineStringField', 'PolygonField', 'SequenceField', 'UUIDField', + 'GeoJsonBaseField'] RECURSIVE_REFERENCE_CONSTANT = 'self' diff --git a/mongoengine/queryset/transform.py b/mongoengine/queryset/transform.py index 2ee7e386..e31a8b7d 100644 --- a/mongoengine/queryset/transform.py +++ b/mongoengine/queryset/transform.py @@ -206,6 +206,10 @@ def update(_doc_cls=None, **update): else: field = cleaned_fields[-1] + GeoJsonBaseField = _import_class("GeoJsonBaseField") + if isinstance(field, GeoJsonBaseField): + value = field.to_mongo(value) + if op in (None, 'set', 'push', 'pull'): if field.required or value is not None: value = field.prepare_query_value(op, value) diff --git a/tests/queryset/geo.py b/tests/queryset/geo.py index f5648961..62e1f668 100644 --- a/tests/queryset/geo.py +++ b/tests/queryset/geo.py @@ -414,5 +414,47 @@ class GeoQueriesTest(unittest.TestCase): roads = Road.objects.filter(poly__geo_intersects={"$geometry": polygon}).count() self.assertEqual(1, roads) + def test_2dsphere_point_sets_correctly(self): + class Location(Document): + loc = PointField() + + Location.drop_collection() + + Location(loc=[1,2]).save() + loc = Location.objects.as_pymongo()[0] + self.assertEquals(loc["loc"], {"type": "Point", "coordinates": [1, 2]}) + + Location.objects.update(set__loc=[2,1]) + loc = Location.objects.as_pymongo()[0] + self.assertEquals(loc["loc"], {"type": "Point", "coordinates": [2, 1]}) + + def test_2dsphere_linestring_sets_correctly(self): + class Location(Document): + line = LineStringField() + + Location.drop_collection() + + Location(line=[[1, 2], [2, 2]]).save() + loc = Location.objects.as_pymongo()[0] + self.assertEquals(loc["line"], {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}) + + Location.objects.update(set__line=[[2, 1], [1, 2]]) + loc = Location.objects.as_pymongo()[0] + self.assertEquals(loc["line"], {"type": "LineString", "coordinates": [[2, 1], [1, 2]]}) + + def test_geojson_PolygonField(self): + class Location(Document): + poly = PolygonField() + + Location.drop_collection() + + Location(poly=[[[40, 5], [40, 6], [41, 6], [40, 5]]]).save() + loc = Location.objects.as_pymongo()[0] + self.assertEquals(loc["poly"], {"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]}) + + Location.objects.update(set__poly=[[[40, 4], [40, 6], [41, 6], [40, 4]]]) + loc = Location.objects.as_pymongo()[0] + self.assertEquals(loc["poly"], {"type": "Polygon", "coordinates": [[[40, 4], [40, 6], [41, 6], [40, 4]]]}) + if __name__ == '__main__': unittest.main() diff --git a/tests/queryset/transform.py b/tests/queryset/transform.py index d2e8b784..2ca67222 100644 --- a/tests/queryset/transform.py +++ b/tests/queryset/transform.py @@ -167,6 +167,35 @@ class TransformTest(unittest.TestCase): {'attachments.views.extracted': 'no'}]} self.assertEqual(expected, raw_query) + def test_geojson_PointField(self): + class Location(Document): + loc = PointField() + + update = transform.update(Location, set__loc=[1, 2]) + self.assertEquals(update, {'$set': {'loc': {"type": "Point", "coordinates": [1,2]}}}) + + update = transform.update(Location, set__loc={"type": "Point", "coordinates": [1,2]}) + self.assertEquals(update, {'$set': {'loc': {"type": "Point", "coordinates": [1,2]}}}) + + def test_geojson_LineStringField(self): + class Location(Document): + line = LineStringField() + + update = transform.update(Location, set__line=[[1, 2], [2, 2]]) + self.assertEquals(update, {'$set': {'line': {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}}}) + + update = transform.update(Location, set__line={"type": "LineString", "coordinates": [[1, 2], [2, 2]]}) + self.assertEquals(update, {'$set': {'line': {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}}}) + + def test_geojson_PolygonField(self): + class Location(Document): + poly = PolygonField() + + update = transform.update(Location, set__poly=[[[40, 5], [40, 6], [41, 6], [40, 5]]]) + self.assertEquals(update, {'$set': {'poly': {"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]}}}) + + update = transform.update(Location, set__poly={"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]}) + self.assertEquals(update, {'$set': {'poly': {"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]}}}) if __name__ == '__main__': unittest.main()