Codebase list djangorestframework-gis / b9a0802
New upstream version 0.14 Michael Fladischer 5 years ago
14 changed file(s) with 1464 addition(s) and 54 deletion(s). Raw diff Collapse all Expand all
00 Changelog
11 =========
2
3 Version 0.14.0 [2018-12-02]
4 ---------------------------
5
6 - `#173 <https://github.com/djangonauts/django-rest-framework-gis/pull/173>`_:
7 added support for django 2.1, DRF 3.9 and switched to django-filters >= 2.0
8 (**which requires python >= 3.4**)
9 - `#178 <https://github.com/djangonauts/django-rest-framework-gis/pull/178>`_:
10 simplified ``setup.py`` and tox build
211
312 Version 0.13.0 [2018-04-27]
413 ---------------------------
11 include LICENSE
22 include README.rst
33 include CHANGES.rst
4 include requirements.txt
5 include runtests.py
64 recursive-include tests *.py
00 Metadata-Version: 1.1
11 Name: djangorestframework-gis
2 Version: 0.13
2 Version: 0.14
33 Summary: Geographic add-ons for Django Rest Framework
44 Home-page: https://github.com/djangonauts/django-rest-framework-gis
55 Author: Douglas Meehan
66 Author-email: django-rest-framework-gis@googlegroups.com
77 License: BSD
88 Download-URL: https://github.com/djangonauts/django-rest-framework-gis/releases
9 Description: UNKNOWN
9 Project-URL: Bug Reports, https://github.com/djangonauts/django-rest-framework-gis/issues
10 Project-URL: Source Code, https://github.com/djangonauts/django-rest-framework-gis
11 Project-URL: Code Coverage, https://coveralls.io/github/djangonauts/django-rest-framework-gis
12 Project-URL: Mailing List, https://groups.google.com/forum/#!forum/django-rest-framework-gis
13 Project-URL: Continuous Integration, https://travis-ci.org/djangonauts/django-rest-framework-gis
14 Description: django-rest-framework-gis
15 =========================
16
17 |Build Status| |Coverage Status| |Requirements Status| |PyPI version|
18
19 Geographic add-ons for Django Rest Framework - `Mailing
20 List <http://bit.ly/1M4sLTp>`__.
21
22 Install last stable version from pypi
23 -------------------------------------
24
25 .. code-block:: bash
26
27 pip install djangorestframework-gis
28
29 Install development version
30 ---------------------------
31
32 .. code-block:: bash
33
34 pip install https://github.com/djangonauts/django-rest-framework-gis/tarball/master
35
36 Setup
37 -----
38
39 Add ``rest_framework_gis`` in ``settings.INSTALLED_APPS``, after ``rest_framework``:
40
41 .. code-block:: python
42
43 INSTALLED_APPS = [
44 # ...
45 'rest_framework',
46 'rest_framework_gis',
47 # ...
48 ]
49
50 Compatibility with DRF, Django and Python
51 -----------------------------------------
52
53 =============== ============================ ==================== ==================================
54 DRF-gis version DRF version Django version Python version
55 **0.14.x** **3.3** to **3.9** **1.11** to **2.1** **3.4** to **3.7**
56 **0.13.x** **3.3** to **3.8** **1.11** to **2.0** **2.7** to **3.6**
57 **0.12.x** **3.1** to **3.7** **1.11** to **2.0** **2.7** to **3.6**
58 **0.11.x** **3.1** to **3.6** **1.7** to **1.11** **2.7** to **3.6**
59 **0.10.x** **3.1** to **3.3** **1.7** to **1.9** **2.7** to **3.5**
60 **0.9.6** **3.1** to **3.2** **1.5** to **1.8** **2.6** to **3.5**
61 **0.9.5** **3.1** to **3.2** **1.5** to **1.8** **2.6** to **3.4**
62 **0.9.4** **3.1** to **3.2** **1.5** to **1.8** **2.6** to **3.4**
63 **0.9.3** **3.1** **1.5** to **1.8** **2.6** to **3.4**
64 **0.9.2** **3.1** **1.5** to **1.8** **2.6** to **3.4**
65 **0.9.1** **3.1** **1.5** to **1.8** **2.6** to **3.4**
66 **0.9** **3.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
67 **0.9** **3.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
68 **0.9** **3.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
69 **0.8.2** **3.0.4** to **3.1.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
70 **0.8.1** **3.0.4** to **3.1.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
71 **0.8** **3.0.4** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
72 **0.7** **2.4.3** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
73 **0.6** **2.4.3** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
74 **0.5** from **2.3.14** to **2.4.2** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
75 **0.4** from **2.3.14** to **2.4.2** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
76 **0.3** from **2.3.14** to **2.4.2** **1.5**, **1.6** **2.6**, **2.7**
77 **0.2** from **2.2.2** to **2.3.13** **1.5**, **1.6** **2.6**, **2.7**
78 =============== ============================ ==================== ==================================
79
80 Fields
81 ------
82
83 GeometryField
84 ~~~~~~~~~~~~~
85
86 Provides a ``GeometryField``, which is a subclass of Django Rest Framework
87 (from now on **DRF**) ``WritableField``. This field handles GeoDjango
88 geometry fields, providing custom ``to_native`` and ``from_native``
89 methods for GeoJSON input/output.
90
91 This field takes two optional arguments:
92
93 ``precision``: Passes coordinates through Python's builtin ``round()`` function (`docs
94 <https://docs.python.org/3/library/functions.html#round>`_), rounding values to
95 the provided level of precision. E.g. A Point with lat/lng of
96 ``[51.0486, -114.0708]`` passed through a ``GeometryField(precision=2)``
97 would return a Point with a lat/lng of ``[51.05, -114.07]``.
98
99 ``remove_duplicates``: Remove sequential duplicate coordinates from line and
100 polygon geometries. This is particularly useful when used with the ``precision``
101 argument, as the likelihood of duplicate coordinates increase as precision of
102 coordinates are reduced.
103
104 **Note:** While both above arguments are designed to reduce the
105 byte size of the API response, they will also increase the processing time
106 required to render the response. This will likely be negligible for small GeoJSON
107 responses but may become an issue for large responses.
108
109 **New in 0.9.3:** there is no need to define this field explicitly in your serializer,
110 it's mapped automatically during initialization in ``rest_framework_gis.apps.AppConfig.ready()``.
111
112 GeometrySerializerMethodField
113 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114
115 Provides a ``GeometrySerializerMethodField``, which is a subclass of DRF
116 ``SerializerMethodField`` and handles values which are computed with a serializer
117 method and are used as a ``geo_field``. `See example below <https://github.com/djangonauts/django-rest-framework-gis#using-geometryserializermethodfield-as-geo_field>`__.
118
119 Serializers
120 -----------
121
122 GeoModelSerializer (DEPRECATED)
123 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124
125 **Deprecated, will be removed in 1.0**: Using this serializer is not needed anymore since 0.9.3 if you add
126 ``rest_framework_gis`` in ``settings.INSTALLED_APPS``
127
128 Provides a ``GeoModelSerializer``, which is a subclass of DRF
129 ``ModelSerializer``. This serializer updates the field\_mapping
130 dictionary to include field mapping of GeoDjango geometry fields to the
131 above ``GeometryField``.
132
133 For example, the following model:
134
135 .. code-block:: python
136
137 class Location(models.Model):
138 """
139 A model which holds information about a particular location
140 """
141 address = models.Charfield(max_length=255)
142 city = models.CharField(max_length=100)
143 state = models.CharField(max_length=100)
144 point = models.PointField()
145
146 By default, the DRF ModelSerializer will output:
147
148 .. code-block:: javascript
149
150 {
151 "id": 1,
152 "address": "742 Evergreen Terrace",
153 "city": "Springfield",
154 "state": "Oregon",
155 "point": "POINT(-123.0208 44.0464)"
156 }
157
158 In contrast, the ``GeoModelSerializer`` will output:
159
160 .. code-block:: javascript
161
162 {
163 "id": 1,
164 "address": "742 Evergreen Terrace",
165 "city": "Springfield",
166 "state": "Oregon",
167 "point": {
168 "type": "Point",
169 "coordinates": [-123.0208, 44.0464],
170 }
171 }
172
173 GeoFeatureModelSerializer
174 ~~~~~~~~~~~~~~~~~~~~~~~~~
175
176 ``GeoFeatureModelSerializer`` is a subclass of ``rest_framework.ModelSerializer``
177 which will output data in a format that is **GeoJSON** compatible. Using
178 the above example, the ``GeoFeatureModelSerializer`` will output:
179
180 .. code-block:: javascript
181
182 {
183 "id": 1,
184 "type": "Feature",
185 "geometry": {
186 "point": {
187 "type": "Point",
188 "coordinates": [-123.0208, 44.0464],
189 },
190 },
191 "properties": {
192 "address": "742 Evergreen Terrace",
193 "city": "Springfield",
194 "state": "Oregon"
195 }
196 }
197
198 If you are serializing an object list, ``GeoFeatureModelSerializer``
199 will create a ``FeatureCollection``:
200
201 .. code-block:: javascript
202
203 {
204 "type": "FeatureCollection",
205 "features": [
206 {
207 "id": 1
208 "type": "Feature",
209 "geometry": {
210 "point": {
211 "type": "Point",
212 "coordinates": [-123.0208, 44.0464],
213 }
214 },
215 "properties": {
216 "address": "742 Evergreen Terrace",
217 "city": "Springfield",
218 "state": "Oregon",
219 }
220 }
221 {
222 "id": 2,
223 "type": "Feature",
224 "geometry": {
225 "point": {
226 "type": "Point",
227 "coordinates": [-123.0208, 44.0489],
228 },
229 },
230 "properties": {
231 "address": "744 Evergreen Terrace",
232 "city": "Springfield",
233 "state": "Oregon"
234 }
235 }
236 }
237
238 Specifying the geometry field: "geo_field"
239 ##########################################
240
241 ``GeoFeatureModelSerializer`` requires you to define a ``geo_field``
242 to be serialized as the "geometry". For example:
243
244 .. code-block:: python
245
246 from rest_framework_gis.serializers import GeoFeatureModelSerializer
247
248 class LocationSerializer(GeoFeatureModelSerializer):
249 """ A class to serialize locations as GeoJSON compatible data """
250
251 class Meta:
252 model = Location
253 geo_field = "point"
254
255 # you can also explicitly declare which fields you want to include
256 # as with a ModelSerializer.
257 fields = ('id', 'address', 'city', 'state')
258
259 Using GeometrySerializerMethodField as "geo_field"
260 ##################################################
261
262 ``geo_field`` may also be an instance of ``GeometrySerializerMethodField``.
263 In this case you can compute its value during serialization. For example:
264
265 .. code-block:: python
266
267 from django.contrib.gis.geos import Point
268 from rest_framework_gis.serializers import GeoFeatureModelSerializer, GeometrySerializerMethodField
269
270 class LocationSerializer(GeoFeatureModelSerializer):
271 """ A class to serialize locations as GeoJSON compatible data """
272
273 # a field which contains a geometry value and can be used as geo_field
274 other_point = GeometrySerializerMethodField()
275
276 def get_other_point(self, obj):
277 return Point(obj.point.lat / 2, obj.point.lon / 2)
278
279 class Meta:
280 model = Location
281 geo_field = 'other_point'
282
283 Serializer for ``geo_field`` may also return ``None`` value, which will translate to ``null`` value for geojson ``geometry`` field.
284
285 Specifying the ID: "id_field"
286 #############################
287
288 The primary key of the model (usually the "id" attribute) is
289 automatically used as the ``id`` field of each
290 `GeoJSON Feature Object <https://tools.ietf.org/html/draft-butler-geojson#section-2.2>`_.
291
292 The default behaviour follows the `GeoJSON RFC <https://tools.ietf.org/html/draft-butler-geojson>`_,
293 but it can be disbaled by setting ``id_field`` to ``False``:
294
295 .. code-block:: python
296
297 from rest_framework_gis.serializers import GeoFeatureModelSerializer
298
299 class LocationSerializer(GeoFeatureModelSerializer):
300
301 class Meta:
302 model = Location
303 geo_field = "point"
304 id_field = False
305 fields = ('id', 'address', 'city', 'state')
306
307 The ``id_field`` can also be set to use some other unique field in your model, eg: ``slug``:
308
309 .. code-block:: python
310
311 from rest_framework_gis.serializers import GeoFeatureModelSerializer
312
313 class LocationSerializer(GeoFeatureModelSerializer):
314
315 class Meta:
316 model = Location
317 geo_field = 'point'
318 id_field = 'slug'
319 fields = ('slug', 'address', 'city', 'state')
320
321 Bounding Box: "auto_bbox" and "bbox_geo_field"
322 ##############################################
323
324 The GeoJSON specification allows a feature to contain a
325 `boundingbox of a feature <http://geojson.org/geojson-spec.html#geojson-objects>`__.
326 ``GeoFeatureModelSerializer`` allows two different ways to fill this property. The first
327 is using the ``geo_field`` to calculate the bounding box of a feature. This only allows
328 read access for a REST client and can be achieved using ``auto_bbox``. Example:
329
330 .. code-block:: python
331
332 from rest_framework_gis.serializers import GeoFeatureModelSerializer
333
334 class LocationSerializer(GeoFeatureModelSerializer):
335 class Meta:
336 model = Location
337 geo_field = 'geometry'
338 auto_bbox = True
339
340
341 The second approach uses the ``bbox_geo_field`` to specify an additional
342 ``GeometryField`` of the model which will be used to calculate the bounding box. This allows
343 boundingboxes differ from the exact extent of a features geometry. Additionally this
344 enables read and write access for the REST client. Bounding boxes send from the client will
345 be saved as Polygons. Example:
346
347 .. code-block:: python
348
349 from rest_framework_gis.serializers import GeoFeatureModelSerializer
350
351 class LocationSerializer(GeoFeatureModelSerializer):
352
353 class Meta:
354 model = BoxedLocation
355 geo_field = 'geometry'
356 bbox_geo_field = 'bbox_geometry'
357
358
359 Custom GeoJSON properties source
360 ################################
361
362 In GeoJSON each feature can have a ``properties`` member containing the
363 attributes of the feature. By default this field is filled with the
364 attributes from your Django model, excluding the id, geometry and bounding
365 box fields. It's possible to override this behaviour and implement a custom
366 source for the ``properties`` member.
367
368 The following example shows how to use a PostgreSQL HStore field as a source for
369 the ``properties`` member:
370
371 .. code-block:: python
372
373 # models.py
374 class Link(models.Model):
375 """
376 Metadata is stored in a PostgreSQL HStore field, which allows us to
377 store arbitrary key-value pairs with a link record.
378 """
379 metadata = HStoreField(blank=True, null=True, default=dict)
380 geo = models.LineStringField()
381 objects = models.GeoManager()
382
383 # serializers.py
384 class NetworkGeoSerializer(GeoFeatureModelSerializer):
385 class Meta:
386 model = models.Link
387 geo_field = 'geo'
388 auto_bbox = True
389
390 def get_properties(self, instance, fields):
391 # This is a PostgreSQL HStore field, which django maps to a dict
392 return instance.metadata
393
394 def unformat_geojson(self, feature):
395 attrs = {
396 self.Meta.geo_field: feature["geometry"],
397 "metadata": feature["properties"]
398 }
399
400 if self.Meta.bbox_geo_field and "bbox" in feature:
401 attrs[self.Meta.bbox_geo_field] = Polygon.from_bbox(feature["bbox"])
402
403 return attrs
404
405 When the serializer renders GeoJSON, it calls the method
406 ``get_properties`` for each object in the database. This function
407 should return a dictionary containing the attributes for the feature. In the
408 case of a HStore field, this function is easily implemented.
409
410 The reverse is also required: mapping a GeoJSON formatted structure to
411 attributes of your model. This task is done by ``unformat_geojson``. It should
412 return a dictionary with your model attributes as keys, and the corresponding
413 values retrieved from the GeoJSON feature data.
414
415 Pagination
416 ----------
417
418 We provide a ``GeoJsonPagination`` class.
419
420 GeoJsonPagination
421 ~~~~~~~~~~~~~~~~~
422
423 Based on ``rest_framework.pagination.PageNumberPagination``.
424
425 Code example:
426
427 .. code-block:: python
428
429 from rest_framework_gis.pagination import GeoJsonPagination
430 # --- other omitted imports --- #
431
432 class GeojsonLocationList(generics.ListCreateAPIView):
433 # -- other omitted view attributes --- #
434 pagination_class = GeoJsonPagination
435
436 Example result response (cut to one element only instead of 10):
437
438 .. code-block:: javascript
439
440 {
441 "type": "FeatureCollection",
442 "count": 25,
443 "next": "http://localhost:8000/geojson/?page=2",
444 "previous": null,
445 "features": [
446 {
447 "type": "Feature",
448 "geometry": {
449 "type": "Point",
450 "coordinates": [
451 42.0,
452 50.0
453 ]
454 },
455 "properties": {
456 "name": "test"
457 }
458 }
459 ]
460 }
461
462
463 Filters
464 -------
465
466 **note**: this feature has been tested up to django-filter 1.0.
467
468 We provide a ``GeometryFilter`` field as well as a ``GeoFilterSet``
469 for usage with ``django_filter``. You simply provide, in the query
470 string, one of the textual types supported by ``GEOSGeometry``. By
471 default, this includes WKT, HEXEWKB, WKB (in a buffer), and GeoJSON.
472
473 GeometryFilter
474 ~~~~~~~~~~~~~~
475
476 .. code-block:: python
477
478 from rest_framework_gis.filterset import GeoFilterSet
479 from rest_framework_gis.filters import GeometryFilter
480 from django_filters import filters
481
482 class RegionFilter(GeoFilterSet):
483 slug = filters.CharFilter(name='slug', lookup_expr='istartswith')
484 contains_geom = GeometryFilter(name='geom', lookup_expr='contains')
485
486 class Meta:
487 model = Region
488
489 We can then filter in the URL, using GeoJSON, and we will perform a
490 ``__contains`` geometry lookup, e.g.
491 ``/region/?contains_geom={ "type": "Point", "coordinates": [ -123.26436996459961, 44.564178042345375 ] }``.
492
493 GeoFilterSet
494 ~~~~~~~~~~~~
495
496 The ``GeoFilterSet`` provides a ``django_filter`` compatible
497 ``FilterSet`` that will automatically create ``GeometryFilters`` for
498 ``GeometryFields``.
499
500 InBBoxFilter
501 ~~~~~~~~~~~~
502
503 Provides a ``InBBoxFilter``, which is a subclass of DRF
504 ``BaseFilterBackend``. Filters a queryset to only those instances within
505 a certain bounding box.
506
507
508 ``views.py:``
509
510 .. code-block:: python
511
512 from rest_framework_gis.filters import InBBoxFilter
513
514 class LocationList(ListAPIView):
515
516 queryset = models.Location.objects.all()
517 serializer_class = serializers.LocationSerializer
518 bbox_filter_field = 'point'
519 filter_backends = (InBBoxFilter, )
520 bbox_filter_include_overlapping = True # Optional
521
522 We can then filter in the URL, using Bounding Box format (min Lon, min
523 Lat, max Lon, max Lat), and we can search for instances within the
524 bounding box, e.g.:
525 ``/location/?in_bbox=-90,29,-89,35``.
526
527 By default, InBBoxFilter will only return those instances entirely
528 within the stated bounding box. To include those instances which overlap
529 the bounding box, include ``bbox_filter_include_overlapping = True``
530 in your view.
531
532 Note that if you are using other filters, you'll want to include your
533 other filter backend in your view. For example:
534
535 ``filter_backends = (InBBoxFilter, DjangoFilterBackend,)``
536
537 TMSTileFilter
538 ~~~~~~~~~~~~~
539
540 Provides a ``TMSTileFilter``, which is a subclass of ``InBBoxFilter``.
541 Filters a queryset to only those instances within a bounding box defined
542 by a `TMS tile <http://wiki.openstreetmap.org/wiki/TMS>`__ address.
543
544 ``views.py:``
545
546 .. code-block:: python
547
548 from rest_framework_gis.filters import TMSTileFilter
549
550 class LocationList(ListAPIView):
551
552 queryset = models.Location.objects.all()
553 serializer_class = serializers.LocationSerializer
554 bbox_filter_field = 'point'
555 filter_backends = (TMSTileFilter, )
556 bbox_filter_include_overlapping = True # Optional
557
558 We can then filter in the URL, using TMS tile addresses in the zoom/x/y format,
559 eg:.
560 ``/location/?tile=8/100/200``
561 which is equivalant to filtering on the bbox (-39.37500,-71.07406,-37.96875,-70.61261).
562
563 For more information on configuration options see InBBoxFilter.
564
565 Note that the tile address start in the upper left, not the lower left origin used by some
566 implementations.
567
568 DistanceToPointFilter
569 ~~~~~~~~~~~~~~~~~~~~~
570
571 Provides a ``DistanceToPointFilter``, which is a subclass of DRF
572 ``BaseFilterBackend``. Filters a queryset to only those instances within
573 a certain distance of a given point.
574
575 ``views.py:``
576
577 .. code-block:: python
578
579 from rest_framework_gis.filters import DistanceToPointFilter
580
581 class LocationList(ListAPIView):
582
583 queryset = models.Location.objects.all()
584 serializer_class = serializers.LocationSerializer
585 distance_filter_field = 'geometry'
586 filter_backends = (DistanceToPointFilter, )
587 bbox_filter_include_overlapping = True # Optional
588
589 We can then filter in the URL, using a distance and a point in (lon, lat) format. The
590 distance can be given in meters or in degrees.
591
592 eg:.
593 ``/location/?dist=4000&point=-122.4862,37.7694&format=json``
594 which is equivalant to filtering within 4000 meters of the point (-122.4862, 37.7694).
595
596 By default, DistanceToPointFilter will pass the 'distance' in the URL directly to the database for the search.
597 The effect depends on the srid of the database in use. If geo data is indexed in meters (srid 3875, aka 900913), a
598 distance in meters can be passed in directly without conversion. For lat-lon databases such as srid 4326,
599 which is indexed in degrees, the 'distance' will be interpreted as degrees. Set the flag, 'distance_filter_convert_meters'
600 to 'True' in order to convert an input distance in meters to degrees. This conversion is approximate, and the errors
601 at latitudes > 60 degrees are > 25%.
602
603 Projects using this package
604 ---------------------------
605
606 - `Nodeshot <https://github.com/ninuxorg/nodeshot>`__: Extensible Django web application for management of community-led georeferenced data
607
608 Running the tests
609 -----------------
610
611 Required setup
612 ==============
613
614 You need one of the `Spatial Database servers supported by
615 GeoDjango <https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#module-django.contrib.gis.db.backends>`__,
616 and create a database for the tests.
617
618 The following can be used with PostgreSQL:
619
620 .. code-block:: bash
621
622 createdb django_restframework_gis
623 psql -U postgres -d django_restframework_gis -c "CREATE EXTENSION postgis"
624
625 You might need to tweak the DB settings according to your DB
626 configuration. You can copy the file ``local_settings.example.py`` to
627 ``local_settings.py`` and change the ``DATABASES`` and/or
628 ``INSTALLED_APPS`` directives there.
629
630 This should allow you to run the tests already.
631
632 For reference, the following steps will setup a development environment for
633 contributing to the project:
634
635 - create a spatial database named "django\_restframework\_gis"
636 - create ``local_settings.py``, eg:
637 ``cp local_settings.example.py local_settings.py``
638 - tweak the ``DATABASES`` configuration directive according to your DB
639 settings
640 - uncomment ``INSTALLED_APPS``
641 - run ``python manage.py syncdb``
642 - run ``python manage.py collectstatic``
643 - run ``python manage.py runserver``
644
645 Using tox
646 =========
647
648 The recommended way to run the tests is by using
649 `tox <https://tox.readthedocs.io/en/latest/>`__, which can be installed using
650 `pip install tox`.
651
652 You can use ``tox -l`` to list the available environments, and then e.g. use
653 the following to run all tests with Python 3.6 and Django 1.11:
654
655 .. code-block:: bash
656
657 tox -e py36-django111
658
659 By default Django's test runner is used, but there is a variation of tox's
660 envlist to use pytest (using the ``-pytest`` suffix).
661
662 You can pass optional arguments to the test runner like this:
663
664 .. code-block:: bash
665
666 tox -e py36-django111-pytest -- -k test_foo
667
668 Running tests manually
669 ======================
670
671 Please refer to the ``tox.ini`` file for reference/help in case you want to run
672 tests manually / without tox.
673
674 To run tests in docker use
675
676 .. code-block:: bash
677 docker-compose build
678 docker-compose run --rm test
679
680
681 Contributing
682 ------------
683
684 1. Join the `Django REST Framework GIS Mailing
685 List <https://groups.google.com/forum/#!forum/django-rest-framework-gis>`__
686 and announce your intentions
687 2. Follow the `PEP8 Style Guide for Python
688 Code <http://www.python.org/dev/peps/pep-0008/>`__
689 3. Fork this repo
690 4. Write code
691 5. Write tests for your code
692 6. Ensure all tests pass
693 7. Ensure test coverage is not under 90%
694 8. Document your changes
695 9. Send pull request
696
697 .. |Build Status| image:: https://travis-ci.org/djangonauts/django-rest-framework-gis.svg?branch=master
698 :target: https://travis-ci.org/djangonauts/django-rest-framework-gis
699 .. |Coverage Status| image:: https://coveralls.io/repos/djangonauts/django-rest-framework-gis/badge.svg
700 :target: https://coveralls.io/r/djangonauts/django-rest-framework-gis
701 .. |Requirements Status| image:: https://requires.io/github/djangonauts/django-rest-framework-gis/requirements.svg?branch=master
702 :target: https://requires.io/github/djangonauts/django-rest-framework-gis/requirements/?branch=master
703 .. |PyPI version| image:: https://badge.fury.io/py/djangorestframework-gis.svg
704 :target: http://badge.fury.io/py/djangorestframework-gis
705
10706 Keywords: django,rest-framework,gis,geojson
11707 Platform: Platform Indipendent
12708 Classifier: Development Status :: 4 - Beta
17713 Classifier: Operating System :: OS Independent
18714 Classifier: Framework :: Django
19715 Classifier: Programming Language :: Python
20 Classifier: Programming Language :: Python :: 2.7
21716 Classifier: Programming Language :: Python :: 3
22 Classifier: Programming Language :: Python :: 3.3
23717 Classifier: Programming Language :: Python :: 3.4
24718 Classifier: Programming Language :: Python :: 3.5
719 Classifier: Programming Language :: Python :: 3.6
720 Classifier: Programming Language :: Python :: 3.7
721 Classifier: Programming Language :: Python :: 3 :: Only
3838
3939 =============== ============================ ==================== ==================================
4040 DRF-gis version DRF version Django version Python version
41 **0.14.x** **3.3** to **3.9** **1.11** to **2.1** **3.4** to **3.7**
4142 **0.13.x** **3.3** to **3.8** **1.11** to **2.0** **2.7** to **3.6**
4243 **0.12.x** **3.1** to **3.7** **1.11** to **2.0** **2.7** to **3.6**
4344 **0.11.x** **3.1** to **3.6** **1.7** to **1.11** **2.7** to **3.6**
656657 Please refer to the ``tox.ini`` file for reference/help in case you want to run
657658 tests manually / without tox.
658659
660 To run tests in docker use
661
662 .. code-block:: bash
663 docker-compose build
664 docker-compose run --rm test
665
666
659667 Contributing
660668 ------------
661669
00 Metadata-Version: 1.1
11 Name: djangorestframework-gis
2 Version: 0.13
2 Version: 0.14
33 Summary: Geographic add-ons for Django Rest Framework
44 Home-page: https://github.com/djangonauts/django-rest-framework-gis
55 Author: Douglas Meehan
66 Author-email: django-rest-framework-gis@googlegroups.com
77 License: BSD
88 Download-URL: https://github.com/djangonauts/django-rest-framework-gis/releases
9 Description: UNKNOWN
9 Project-URL: Bug Reports, https://github.com/djangonauts/django-rest-framework-gis/issues
10 Project-URL: Source Code, https://github.com/djangonauts/django-rest-framework-gis
11 Project-URL: Code Coverage, https://coveralls.io/github/djangonauts/django-rest-framework-gis
12 Project-URL: Mailing List, https://groups.google.com/forum/#!forum/django-rest-framework-gis
13 Project-URL: Continuous Integration, https://travis-ci.org/djangonauts/django-rest-framework-gis
14 Description: django-rest-framework-gis
15 =========================
16
17 |Build Status| |Coverage Status| |Requirements Status| |PyPI version|
18
19 Geographic add-ons for Django Rest Framework - `Mailing
20 List <http://bit.ly/1M4sLTp>`__.
21
22 Install last stable version from pypi
23 -------------------------------------
24
25 .. code-block:: bash
26
27 pip install djangorestframework-gis
28
29 Install development version
30 ---------------------------
31
32 .. code-block:: bash
33
34 pip install https://github.com/djangonauts/django-rest-framework-gis/tarball/master
35
36 Setup
37 -----
38
39 Add ``rest_framework_gis`` in ``settings.INSTALLED_APPS``, after ``rest_framework``:
40
41 .. code-block:: python
42
43 INSTALLED_APPS = [
44 # ...
45 'rest_framework',
46 'rest_framework_gis',
47 # ...
48 ]
49
50 Compatibility with DRF, Django and Python
51 -----------------------------------------
52
53 =============== ============================ ==================== ==================================
54 DRF-gis version DRF version Django version Python version
55 **0.14.x** **3.3** to **3.9** **1.11** to **2.1** **3.4** to **3.7**
56 **0.13.x** **3.3** to **3.8** **1.11** to **2.0** **2.7** to **3.6**
57 **0.12.x** **3.1** to **3.7** **1.11** to **2.0** **2.7** to **3.6**
58 **0.11.x** **3.1** to **3.6** **1.7** to **1.11** **2.7** to **3.6**
59 **0.10.x** **3.1** to **3.3** **1.7** to **1.9** **2.7** to **3.5**
60 **0.9.6** **3.1** to **3.2** **1.5** to **1.8** **2.6** to **3.5**
61 **0.9.5** **3.1** to **3.2** **1.5** to **1.8** **2.6** to **3.4**
62 **0.9.4** **3.1** to **3.2** **1.5** to **1.8** **2.6** to **3.4**
63 **0.9.3** **3.1** **1.5** to **1.8** **2.6** to **3.4**
64 **0.9.2** **3.1** **1.5** to **1.8** **2.6** to **3.4**
65 **0.9.1** **3.1** **1.5** to **1.8** **2.6** to **3.4**
66 **0.9** **3.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
67 **0.9** **3.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
68 **0.9** **3.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
69 **0.8.2** **3.0.4** to **3.1.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
70 **0.8.1** **3.0.4** to **3.1.1** **1.5** to **1.8** **2.6**, **2.7**, **3.3**, **3.4**
71 **0.8** **3.0.4** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
72 **0.7** **2.4.3** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
73 **0.6** **2.4.3** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
74 **0.5** from **2.3.14** to **2.4.2** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
75 **0.4** from **2.3.14** to **2.4.2** **1.5** to **1.7** **2.6**, **2.7**, **3.3**, **3.4**
76 **0.3** from **2.3.14** to **2.4.2** **1.5**, **1.6** **2.6**, **2.7**
77 **0.2** from **2.2.2** to **2.3.13** **1.5**, **1.6** **2.6**, **2.7**
78 =============== ============================ ==================== ==================================
79
80 Fields
81 ------
82
83 GeometryField
84 ~~~~~~~~~~~~~
85
86 Provides a ``GeometryField``, which is a subclass of Django Rest Framework
87 (from now on **DRF**) ``WritableField``. This field handles GeoDjango
88 geometry fields, providing custom ``to_native`` and ``from_native``
89 methods for GeoJSON input/output.
90
91 This field takes two optional arguments:
92
93 ``precision``: Passes coordinates through Python's builtin ``round()`` function (`docs
94 <https://docs.python.org/3/library/functions.html#round>`_), rounding values to
95 the provided level of precision. E.g. A Point with lat/lng of
96 ``[51.0486, -114.0708]`` passed through a ``GeometryField(precision=2)``
97 would return a Point with a lat/lng of ``[51.05, -114.07]``.
98
99 ``remove_duplicates``: Remove sequential duplicate coordinates from line and
100 polygon geometries. This is particularly useful when used with the ``precision``
101 argument, as the likelihood of duplicate coordinates increase as precision of
102 coordinates are reduced.
103
104 **Note:** While both above arguments are designed to reduce the
105 byte size of the API response, they will also increase the processing time
106 required to render the response. This will likely be negligible for small GeoJSON
107 responses but may become an issue for large responses.
108
109 **New in 0.9.3:** there is no need to define this field explicitly in your serializer,
110 it's mapped automatically during initialization in ``rest_framework_gis.apps.AppConfig.ready()``.
111
112 GeometrySerializerMethodField
113 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114
115 Provides a ``GeometrySerializerMethodField``, which is a subclass of DRF
116 ``SerializerMethodField`` and handles values which are computed with a serializer
117 method and are used as a ``geo_field``. `See example below <https://github.com/djangonauts/django-rest-framework-gis#using-geometryserializermethodfield-as-geo_field>`__.
118
119 Serializers
120 -----------
121
122 GeoModelSerializer (DEPRECATED)
123 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124
125 **Deprecated, will be removed in 1.0**: Using this serializer is not needed anymore since 0.9.3 if you add
126 ``rest_framework_gis`` in ``settings.INSTALLED_APPS``
127
128 Provides a ``GeoModelSerializer``, which is a subclass of DRF
129 ``ModelSerializer``. This serializer updates the field\_mapping
130 dictionary to include field mapping of GeoDjango geometry fields to the
131 above ``GeometryField``.
132
133 For example, the following model:
134
135 .. code-block:: python
136
137 class Location(models.Model):
138 """
139 A model which holds information about a particular location
140 """
141 address = models.Charfield(max_length=255)
142 city = models.CharField(max_length=100)
143 state = models.CharField(max_length=100)
144 point = models.PointField()
145
146 By default, the DRF ModelSerializer will output:
147
148 .. code-block:: javascript
149
150 {
151 "id": 1,
152 "address": "742 Evergreen Terrace",
153 "city": "Springfield",
154 "state": "Oregon",
155 "point": "POINT(-123.0208 44.0464)"
156 }
157
158 In contrast, the ``GeoModelSerializer`` will output:
159
160 .. code-block:: javascript
161
162 {
163 "id": 1,
164 "address": "742 Evergreen Terrace",
165 "city": "Springfield",
166 "state": "Oregon",
167 "point": {
168 "type": "Point",
169 "coordinates": [-123.0208, 44.0464],
170 }
171 }
172
173 GeoFeatureModelSerializer
174 ~~~~~~~~~~~~~~~~~~~~~~~~~
175
176 ``GeoFeatureModelSerializer`` is a subclass of ``rest_framework.ModelSerializer``
177 which will output data in a format that is **GeoJSON** compatible. Using
178 the above example, the ``GeoFeatureModelSerializer`` will output:
179
180 .. code-block:: javascript
181
182 {
183 "id": 1,
184 "type": "Feature",
185 "geometry": {
186 "point": {
187 "type": "Point",
188 "coordinates": [-123.0208, 44.0464],
189 },
190 },
191 "properties": {
192 "address": "742 Evergreen Terrace",
193 "city": "Springfield",
194 "state": "Oregon"
195 }
196 }
197
198 If you are serializing an object list, ``GeoFeatureModelSerializer``
199 will create a ``FeatureCollection``:
200
201 .. code-block:: javascript
202
203 {
204 "type": "FeatureCollection",
205 "features": [
206 {
207 "id": 1
208 "type": "Feature",
209 "geometry": {
210 "point": {
211 "type": "Point",
212 "coordinates": [-123.0208, 44.0464],
213 }
214 },
215 "properties": {
216 "address": "742 Evergreen Terrace",
217 "city": "Springfield",
218 "state": "Oregon",
219 }
220 }
221 {
222 "id": 2,
223 "type": "Feature",
224 "geometry": {
225 "point": {
226 "type": "Point",
227 "coordinates": [-123.0208, 44.0489],
228 },
229 },
230 "properties": {
231 "address": "744 Evergreen Terrace",
232 "city": "Springfield",
233 "state": "Oregon"
234 }
235 }
236 }
237
238 Specifying the geometry field: "geo_field"
239 ##########################################
240
241 ``GeoFeatureModelSerializer`` requires you to define a ``geo_field``
242 to be serialized as the "geometry". For example:
243
244 .. code-block:: python
245
246 from rest_framework_gis.serializers import GeoFeatureModelSerializer
247
248 class LocationSerializer(GeoFeatureModelSerializer):
249 """ A class to serialize locations as GeoJSON compatible data """
250
251 class Meta:
252 model = Location
253 geo_field = "point"
254
255 # you can also explicitly declare which fields you want to include
256 # as with a ModelSerializer.
257 fields = ('id', 'address', 'city', 'state')
258
259 Using GeometrySerializerMethodField as "geo_field"
260 ##################################################
261
262 ``geo_field`` may also be an instance of ``GeometrySerializerMethodField``.
263 In this case you can compute its value during serialization. For example:
264
265 .. code-block:: python
266
267 from django.contrib.gis.geos import Point
268 from rest_framework_gis.serializers import GeoFeatureModelSerializer, GeometrySerializerMethodField
269
270 class LocationSerializer(GeoFeatureModelSerializer):
271 """ A class to serialize locations as GeoJSON compatible data """
272
273 # a field which contains a geometry value and can be used as geo_field
274 other_point = GeometrySerializerMethodField()
275
276 def get_other_point(self, obj):
277 return Point(obj.point.lat / 2, obj.point.lon / 2)
278
279 class Meta:
280 model = Location
281 geo_field = 'other_point'
282
283 Serializer for ``geo_field`` may also return ``None`` value, which will translate to ``null`` value for geojson ``geometry`` field.
284
285 Specifying the ID: "id_field"
286 #############################
287
288 The primary key of the model (usually the "id" attribute) is
289 automatically used as the ``id`` field of each
290 `GeoJSON Feature Object <https://tools.ietf.org/html/draft-butler-geojson#section-2.2>`_.
291
292 The default behaviour follows the `GeoJSON RFC <https://tools.ietf.org/html/draft-butler-geojson>`_,
293 but it can be disbaled by setting ``id_field`` to ``False``:
294
295 .. code-block:: python
296
297 from rest_framework_gis.serializers import GeoFeatureModelSerializer
298
299 class LocationSerializer(GeoFeatureModelSerializer):
300
301 class Meta:
302 model = Location
303 geo_field = "point"
304 id_field = False
305 fields = ('id', 'address', 'city', 'state')
306
307 The ``id_field`` can also be set to use some other unique field in your model, eg: ``slug``:
308
309 .. code-block:: python
310
311 from rest_framework_gis.serializers import GeoFeatureModelSerializer
312
313 class LocationSerializer(GeoFeatureModelSerializer):
314
315 class Meta:
316 model = Location
317 geo_field = 'point'
318 id_field = 'slug'
319 fields = ('slug', 'address', 'city', 'state')
320
321 Bounding Box: "auto_bbox" and "bbox_geo_field"
322 ##############################################
323
324 The GeoJSON specification allows a feature to contain a
325 `boundingbox of a feature <http://geojson.org/geojson-spec.html#geojson-objects>`__.
326 ``GeoFeatureModelSerializer`` allows two different ways to fill this property. The first
327 is using the ``geo_field`` to calculate the bounding box of a feature. This only allows
328 read access for a REST client and can be achieved using ``auto_bbox``. Example:
329
330 .. code-block:: python
331
332 from rest_framework_gis.serializers import GeoFeatureModelSerializer
333
334 class LocationSerializer(GeoFeatureModelSerializer):
335 class Meta:
336 model = Location
337 geo_field = 'geometry'
338 auto_bbox = True
339
340
341 The second approach uses the ``bbox_geo_field`` to specify an additional
342 ``GeometryField`` of the model which will be used to calculate the bounding box. This allows
343 boundingboxes differ from the exact extent of a features geometry. Additionally this
344 enables read and write access for the REST client. Bounding boxes send from the client will
345 be saved as Polygons. Example:
346
347 .. code-block:: python
348
349 from rest_framework_gis.serializers import GeoFeatureModelSerializer
350
351 class LocationSerializer(GeoFeatureModelSerializer):
352
353 class Meta:
354 model = BoxedLocation
355 geo_field = 'geometry'
356 bbox_geo_field = 'bbox_geometry'
357
358
359 Custom GeoJSON properties source
360 ################################
361
362 In GeoJSON each feature can have a ``properties`` member containing the
363 attributes of the feature. By default this field is filled with the
364 attributes from your Django model, excluding the id, geometry and bounding
365 box fields. It's possible to override this behaviour and implement a custom
366 source for the ``properties`` member.
367
368 The following example shows how to use a PostgreSQL HStore field as a source for
369 the ``properties`` member:
370
371 .. code-block:: python
372
373 # models.py
374 class Link(models.Model):
375 """
376 Metadata is stored in a PostgreSQL HStore field, which allows us to
377 store arbitrary key-value pairs with a link record.
378 """
379 metadata = HStoreField(blank=True, null=True, default=dict)
380 geo = models.LineStringField()
381 objects = models.GeoManager()
382
383 # serializers.py
384 class NetworkGeoSerializer(GeoFeatureModelSerializer):
385 class Meta:
386 model = models.Link
387 geo_field = 'geo'
388 auto_bbox = True
389
390 def get_properties(self, instance, fields):
391 # This is a PostgreSQL HStore field, which django maps to a dict
392 return instance.metadata
393
394 def unformat_geojson(self, feature):
395 attrs = {
396 self.Meta.geo_field: feature["geometry"],
397 "metadata": feature["properties"]
398 }
399
400 if self.Meta.bbox_geo_field and "bbox" in feature:
401 attrs[self.Meta.bbox_geo_field] = Polygon.from_bbox(feature["bbox"])
402
403 return attrs
404
405 When the serializer renders GeoJSON, it calls the method
406 ``get_properties`` for each object in the database. This function
407 should return a dictionary containing the attributes for the feature. In the
408 case of a HStore field, this function is easily implemented.
409
410 The reverse is also required: mapping a GeoJSON formatted structure to
411 attributes of your model. This task is done by ``unformat_geojson``. It should
412 return a dictionary with your model attributes as keys, and the corresponding
413 values retrieved from the GeoJSON feature data.
414
415 Pagination
416 ----------
417
418 We provide a ``GeoJsonPagination`` class.
419
420 GeoJsonPagination
421 ~~~~~~~~~~~~~~~~~
422
423 Based on ``rest_framework.pagination.PageNumberPagination``.
424
425 Code example:
426
427 .. code-block:: python
428
429 from rest_framework_gis.pagination import GeoJsonPagination
430 # --- other omitted imports --- #
431
432 class GeojsonLocationList(generics.ListCreateAPIView):
433 # -- other omitted view attributes --- #
434 pagination_class = GeoJsonPagination
435
436 Example result response (cut to one element only instead of 10):
437
438 .. code-block:: javascript
439
440 {
441 "type": "FeatureCollection",
442 "count": 25,
443 "next": "http://localhost:8000/geojson/?page=2",
444 "previous": null,
445 "features": [
446 {
447 "type": "Feature",
448 "geometry": {
449 "type": "Point",
450 "coordinates": [
451 42.0,
452 50.0
453 ]
454 },
455 "properties": {
456 "name": "test"
457 }
458 }
459 ]
460 }
461
462
463 Filters
464 -------
465
466 **note**: this feature has been tested up to django-filter 1.0.
467
468 We provide a ``GeometryFilter`` field as well as a ``GeoFilterSet``
469 for usage with ``django_filter``. You simply provide, in the query
470 string, one of the textual types supported by ``GEOSGeometry``. By
471 default, this includes WKT, HEXEWKB, WKB (in a buffer), and GeoJSON.
472
473 GeometryFilter
474 ~~~~~~~~~~~~~~
475
476 .. code-block:: python
477
478 from rest_framework_gis.filterset import GeoFilterSet
479 from rest_framework_gis.filters import GeometryFilter
480 from django_filters import filters
481
482 class RegionFilter(GeoFilterSet):
483 slug = filters.CharFilter(name='slug', lookup_expr='istartswith')
484 contains_geom = GeometryFilter(name='geom', lookup_expr='contains')
485
486 class Meta:
487 model = Region
488
489 We can then filter in the URL, using GeoJSON, and we will perform a
490 ``__contains`` geometry lookup, e.g.
491 ``/region/?contains_geom={ "type": "Point", "coordinates": [ -123.26436996459961, 44.564178042345375 ] }``.
492
493 GeoFilterSet
494 ~~~~~~~~~~~~
495
496 The ``GeoFilterSet`` provides a ``django_filter`` compatible
497 ``FilterSet`` that will automatically create ``GeometryFilters`` for
498 ``GeometryFields``.
499
500 InBBoxFilter
501 ~~~~~~~~~~~~
502
503 Provides a ``InBBoxFilter``, which is a subclass of DRF
504 ``BaseFilterBackend``. Filters a queryset to only those instances within
505 a certain bounding box.
506
507
508 ``views.py:``
509
510 .. code-block:: python
511
512 from rest_framework_gis.filters import InBBoxFilter
513
514 class LocationList(ListAPIView):
515
516 queryset = models.Location.objects.all()
517 serializer_class = serializers.LocationSerializer
518 bbox_filter_field = 'point'
519 filter_backends = (InBBoxFilter, )
520 bbox_filter_include_overlapping = True # Optional
521
522 We can then filter in the URL, using Bounding Box format (min Lon, min
523 Lat, max Lon, max Lat), and we can search for instances within the
524 bounding box, e.g.:
525 ``/location/?in_bbox=-90,29,-89,35``.
526
527 By default, InBBoxFilter will only return those instances entirely
528 within the stated bounding box. To include those instances which overlap
529 the bounding box, include ``bbox_filter_include_overlapping = True``
530 in your view.
531
532 Note that if you are using other filters, you'll want to include your
533 other filter backend in your view. For example:
534
535 ``filter_backends = (InBBoxFilter, DjangoFilterBackend,)``
536
537 TMSTileFilter
538 ~~~~~~~~~~~~~
539
540 Provides a ``TMSTileFilter``, which is a subclass of ``InBBoxFilter``.
541 Filters a queryset to only those instances within a bounding box defined
542 by a `TMS tile <http://wiki.openstreetmap.org/wiki/TMS>`__ address.
543
544 ``views.py:``
545
546 .. code-block:: python
547
548 from rest_framework_gis.filters import TMSTileFilter
549
550 class LocationList(ListAPIView):
551
552 queryset = models.Location.objects.all()
553 serializer_class = serializers.LocationSerializer
554 bbox_filter_field = 'point'
555 filter_backends = (TMSTileFilter, )
556 bbox_filter_include_overlapping = True # Optional
557
558 We can then filter in the URL, using TMS tile addresses in the zoom/x/y format,
559 eg:.
560 ``/location/?tile=8/100/200``
561 which is equivalant to filtering on the bbox (-39.37500,-71.07406,-37.96875,-70.61261).
562
563 For more information on configuration options see InBBoxFilter.
564
565 Note that the tile address start in the upper left, not the lower left origin used by some
566 implementations.
567
568 DistanceToPointFilter
569 ~~~~~~~~~~~~~~~~~~~~~
570
571 Provides a ``DistanceToPointFilter``, which is a subclass of DRF
572 ``BaseFilterBackend``. Filters a queryset to only those instances within
573 a certain distance of a given point.
574
575 ``views.py:``
576
577 .. code-block:: python
578
579 from rest_framework_gis.filters import DistanceToPointFilter
580
581 class LocationList(ListAPIView):
582
583 queryset = models.Location.objects.all()
584 serializer_class = serializers.LocationSerializer
585 distance_filter_field = 'geometry'
586 filter_backends = (DistanceToPointFilter, )
587 bbox_filter_include_overlapping = True # Optional
588
589 We can then filter in the URL, using a distance and a point in (lon, lat) format. The
590 distance can be given in meters or in degrees.
591
592 eg:.
593 ``/location/?dist=4000&point=-122.4862,37.7694&format=json``
594 which is equivalant to filtering within 4000 meters of the point (-122.4862, 37.7694).
595
596 By default, DistanceToPointFilter will pass the 'distance' in the URL directly to the database for the search.
597 The effect depends on the srid of the database in use. If geo data is indexed in meters (srid 3875, aka 900913), a
598 distance in meters can be passed in directly without conversion. For lat-lon databases such as srid 4326,
599 which is indexed in degrees, the 'distance' will be interpreted as degrees. Set the flag, 'distance_filter_convert_meters'
600 to 'True' in order to convert an input distance in meters to degrees. This conversion is approximate, and the errors
601 at latitudes > 60 degrees are > 25%.
602
603 Projects using this package
604 ---------------------------
605
606 - `Nodeshot <https://github.com/ninuxorg/nodeshot>`__: Extensible Django web application for management of community-led georeferenced data
607
608 Running the tests
609 -----------------
610
611 Required setup
612 ==============
613
614 You need one of the `Spatial Database servers supported by
615 GeoDjango <https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#module-django.contrib.gis.db.backends>`__,
616 and create a database for the tests.
617
618 The following can be used with PostgreSQL:
619
620 .. code-block:: bash
621
622 createdb django_restframework_gis
623 psql -U postgres -d django_restframework_gis -c "CREATE EXTENSION postgis"
624
625 You might need to tweak the DB settings according to your DB
626 configuration. You can copy the file ``local_settings.example.py`` to
627 ``local_settings.py`` and change the ``DATABASES`` and/or
628 ``INSTALLED_APPS`` directives there.
629
630 This should allow you to run the tests already.
631
632 For reference, the following steps will setup a development environment for
633 contributing to the project:
634
635 - create a spatial database named "django\_restframework\_gis"
636 - create ``local_settings.py``, eg:
637 ``cp local_settings.example.py local_settings.py``
638 - tweak the ``DATABASES`` configuration directive according to your DB
639 settings
640 - uncomment ``INSTALLED_APPS``
641 - run ``python manage.py syncdb``
642 - run ``python manage.py collectstatic``
643 - run ``python manage.py runserver``
644
645 Using tox
646 =========
647
648 The recommended way to run the tests is by using
649 `tox <https://tox.readthedocs.io/en/latest/>`__, which can be installed using
650 `pip install tox`.
651
652 You can use ``tox -l`` to list the available environments, and then e.g. use
653 the following to run all tests with Python 3.6 and Django 1.11:
654
655 .. code-block:: bash
656
657 tox -e py36-django111
658
659 By default Django's test runner is used, but there is a variation of tox's
660 envlist to use pytest (using the ``-pytest`` suffix).
661
662 You can pass optional arguments to the test runner like this:
663
664 .. code-block:: bash
665
666 tox -e py36-django111-pytest -- -k test_foo
667
668 Running tests manually
669 ======================
670
671 Please refer to the ``tox.ini`` file for reference/help in case you want to run
672 tests manually / without tox.
673
674 To run tests in docker use
675
676 .. code-block:: bash
677 docker-compose build
678 docker-compose run --rm test
679
680
681 Contributing
682 ------------
683
684 1. Join the `Django REST Framework GIS Mailing
685 List <https://groups.google.com/forum/#!forum/django-rest-framework-gis>`__
686 and announce your intentions
687 2. Follow the `PEP8 Style Guide for Python
688 Code <http://www.python.org/dev/peps/pep-0008/>`__
689 3. Fork this repo
690 4. Write code
691 5. Write tests for your code
692 6. Ensure all tests pass
693 7. Ensure test coverage is not under 90%
694 8. Document your changes
695 9. Send pull request
696
697 .. |Build Status| image:: https://travis-ci.org/djangonauts/django-rest-framework-gis.svg?branch=master
698 :target: https://travis-ci.org/djangonauts/django-rest-framework-gis
699 .. |Coverage Status| image:: https://coveralls.io/repos/djangonauts/django-rest-framework-gis/badge.svg
700 :target: https://coveralls.io/r/djangonauts/django-rest-framework-gis
701 .. |Requirements Status| image:: https://requires.io/github/djangonauts/django-rest-framework-gis/requirements.svg?branch=master
702 :target: https://requires.io/github/djangonauts/django-rest-framework-gis/requirements/?branch=master
703 .. |PyPI version| image:: https://badge.fury.io/py/djangorestframework-gis.svg
704 :target: http://badge.fury.io/py/djangorestframework-gis
705
10706 Keywords: django,rest-framework,gis,geojson
11707 Platform: Platform Indipendent
12708 Classifier: Development Status :: 4 - Beta
17713 Classifier: Operating System :: OS Independent
18714 Classifier: Framework :: Django
19715 Classifier: Programming Language :: Python
20 Classifier: Programming Language :: Python :: 2.7
21716 Classifier: Programming Language :: Python :: 3
22 Classifier: Programming Language :: Python :: 3.3
23717 Classifier: Programming Language :: Python :: 3.4
24718 Classifier: Programming Language :: Python :: 3.5
719 Classifier: Programming Language :: Python :: 3.6
720 Classifier: Programming Language :: Python :: 3.7
721 Classifier: Programming Language :: Python :: 3 :: Only
33 MANIFEST.in
44 README.rst
55 requirements.txt
6 runtests.py
76 setup.cfg
87 setup.py
98 djangorestframework_gis.egg-info/PKG-INFO
0 six
1 djangorestframework<3.9,>=3.3
0 djangorestframework
0 six
1 djangorestframework>=3.3,<3.9
0 djangorestframework>=3.3,<3.10
0 VERSION = (0, 13, 0, 'final')
0 VERSION = (0, 14, 0, 'final')
11 __version__ = VERSION # alias
22
33
0 import six # TODO Remove this along with GeoJsonDict when support for python 2.6/2.7 is dropped.
10 import json
21 from collections import OrderedDict
32
43 from django.contrib.gis.geos import GEOSGeometry, GEOSException
54 from django.contrib.gis.gdal import GDALException
65 from django.core.exceptions import ValidationError
6 from django.utils import six # TODO Remove this along with GeoJsonDict when support for python 2.6/2.7 is dropped.
77 from django.utils.translation import ugettext_lazy as _
88 from rest_framework.fields import Field, SerializerMethodField
99
+0
-15
runtests.py less more
0 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2
3 import os
4 import sys
5
6 sys.path.insert(0, "tests")
7 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
8
9 if __name__ == "__main__":
10 from django.core.management import execute_from_command_line
11 args = sys.argv
12 args.insert(1, "test")
13 args.insert(2, "django_restframework_gis_tests")
14 execute_from_command_line(args)
00 #!/usr/bin/env python
1 import os
12 import sys
2 import os
3 from setuptools import setup, find_packages
3
4 from setuptools import find_packages, setup
5
46 from rest_framework_gis import get_version
5
6
7 def get_install_requires():
8 """
9 parse requirements.txt, ignore links, exclude comments
10 """
11 requirements = []
12 for line in open('requirements.txt').readlines():
13 # skip to next iteration if comment or empty line
14 if line.startswith('#') or line == '' or line.startswith('http') or line.startswith('git'):
15 continue
16 # add line to requirements
17 requirements.append(line)
18 return requirements
19
207
218 if sys.argv[-1] == 'publish':
229 os.system("python setup.py sdist bdist_wheel")
2815 print(" git push --tags")
2916 sys.exit()
3017
18 here = os.path.abspath(os.path.dirname(__file__))
19
20 # Get the long description from the README file
21 with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f:
22 long_description = f.read()
23
3124
3225 setup(
3326 name='djangorestframework-gis',
3629 author='Douglas Meehan',
3730 author_email='django-rest-framework-gis@googlegroups.com',
3831 description='Geographic add-ons for Django Rest Framework',
32 long_description=long_description,
3933 url='https://github.com/djangonauts/django-rest-framework-gis',
4034 download_url='https://github.com/djangonauts/django-rest-framework-gis/releases',
4135 platforms=['Platform Indipendent'],
4236 keywords=['django', 'rest-framework', 'gis', 'geojson'],
4337 packages=find_packages(exclude=['tests', 'tests.*']),
44 install_requires=get_install_requires(),
38 install_requires=[
39 'djangorestframework',
40 ],
4541 classifiers=[
4642 'Development Status :: 4 - Beta',
4743 'Environment :: Web Environment',
5147 'Operating System :: OS Independent',
5248 'Framework :: Django',
5349 'Programming Language :: Python',
54 'Programming Language :: Python :: 2.7',
5550 'Programming Language :: Python :: 3',
56 'Programming Language :: Python :: 3.3',
5751 'Programming Language :: Python :: 3.4',
5852 'Programming Language :: Python :: 3.5',
59 ]
53 'Programming Language :: Python :: 3.6',
54 'Programming Language :: Python :: 3.7',
55 'Programming Language :: Python :: 3 :: Only',
56 ],
57 project_urls={
58 'Bug Reports': 'https://github.com/djangonauts/django-rest-framework-gis/issues',
59 'Continuous Integration': 'https://travis-ci.org/djangonauts/django-rest-framework-gis',
60 'Mailing List': 'https://groups.google.com/forum/#!forum/django-rest-framework-gis',
61 'Code Coverage': 'https://coveralls.io/github/djangonauts/django-rest-framework-gis',
62 'Source Code': 'https://github.com/djangonauts/django-rest-framework-gis',
63 },
6064 )
66 import sys
77 import json
88 import pickle
9
10 from unittest import skipIf
911
1012 from django.test import TestCase
1113 from django.contrib.gis.geos import GEOSGeometry, Polygon, Point
1517 from django.core.urlresolvers import reverse
1618 from django.core.exceptions import ImproperlyConfigured
1719
20 import rest_framework
21
1822 from rest_framework_gis import serializers as gis_serializers
1923 from rest_framework_gis.fields import GeoJsonDict
2024
2125 from .models import Location, LocatedFile
2226 from .serializers import LocationGeoSerializer
27
28 is_pre_drf_39 = not rest_framework.VERSION.startswith('3.9')
2329
2430
2531 class TestRestFrameworkGis(TestCase):
471477 location = Location.objects.all()[0]
472478 self.assertEqual(location.name, "HTML test WKT")
473479
480 @skipIf(is_pre_drf_39, 'Skip this test if DRF < 3.9')
474481 def test_geojson_HTML_widget_value(self):
482 self._create_locations()
483 response = self.client.get(self.geojson_location_list_url, HTTP_ACCEPT='text/html')
484 self.assertContains(response, '<textarea name="geometry"')
485 self.assertContains(response, '"type": "Point"')
486 self.assertContains(response, '"coordinates": [')
487
488 @skipIf(not is_pre_drf_39, 'Skip this test if DRF >= 3.9')
489 def test_geojson_HTML_widget_value_pre_drf_39(self):
475490 self._create_locations()
476491 response = self.client.get(self.geojson_location_list_url, HTTP_ACCEPT='text/html')
477492 self.assertContains(response, '<textarea name="geometry"')
131131
132132
133133 class LocationFilter(GeoFilterSet):
134 contains_properly = GeometryFilter(name='geometry',
134 contains_properly = GeometryFilter(field_name='geometry',
135135 lookup_expr='contains_properly')
136136
137137 class Meta: