Metadata-Version: 1.1
Name: django-loci
Version: 0.4.3
Summary: Reusable django-app for outdoor and indoor mapping
Home-page: http://openwisp.org
Author: Federico Capoano
Author-email: support@openwisp.io
License: BSD
Download-URL: https://github.com/openwisp/django-loci/releases
Description: django-loci
        ===========
        
        .. image:: https://travis-ci.org/openwisp/django-loci.svg
           :target: https://travis-ci.org/openwisp/django-loci
        
        .. image:: https://coveralls.io/repos/openwisp/django-loci/badge.svg
           :target: https://coveralls.io/r/openwisp/django-loci
        
        .. image:: https://requires.io/github/openwisp/django-loci/requirements.svg?branch=master
           :target: https://requires.io/github/openwisp/django-loci/requirements/?branch=master
           :alt: Requirements Status
        
        .. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square
           :target: https://gitter.im/openwisp/general
        
        .. image:: https://badge.fury.io/py/django-loci.svg
           :target: http://badge.fury.io/py/django-loci
        
        .. image:: https://pepy.tech/badge/django-loci
           :target: https://pepy.tech/project/django-loci
           :alt: downloads
        
        .. image:: https://img.shields.io/badge/code%20style-black-000000.svg
           :target: https://pypi.org/project/black/
           :alt: code style: black
        
        ------------
        
        Reusable django-app for storing GIS and indoor coordinates of objects.
        
        .. image:: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/indoor.png
           :target: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/indoor.png
           :alt: Indoor coordinates
        
        .. image:: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/map.png
           :target: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/map.png
           :alt: Map coordinates
        
        .. image:: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/mobile.png
           :target: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/mobile.png
           :alt: Mobile coordinates
        
        ------------
        
        .. contents:: **Table of Contents**:
           :backlinks: none
           :depth: 3
        
        ------------
        
        Dependencies
        ------------
        
        * Python >= 3.6
        * GeoDjango (`see GeoDjango Install Instructions <https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/#requirements>`_)
        * One of the databases supported by GeoDjango
        
        
        Compatibility Table
        -------------------
        
        ===============  ==================================
        django-loci      Python version
        0.2              2.7 or >=3.4
        0.3              >=3.6
        ===============  ==================================
        
        
        Install stable version from pypi
        --------------------------------
        
        Install from pypi:
        
        .. code-block:: shell
        
            pip install django-loci
        
        Install development version
        ---------------------------
        
        First of all, install the dependencies of `GeoDjango <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/>`_:
        
        - `Geospatial libraries <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/geolibs/>`_
        - `Spatial database <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/spatialite/>`_,
          for development we use Spatialite, a spatial extension of `sqlite <https://www.sqlite.org/index.html>`_
        
        Install tarball:
        
        .. code-block:: shell
        
            pip install https://github.com/openwisp/django-loci/tarball/master
        
        Alternatively you can install via pip using git:
        
        .. code-block:: shell
        
            pip install -e git+git://github.com/openwisp/django-loci#egg=django_loci
        
        If you want to contribute, install your cloned fork:
        
        .. code-block:: shell
        
            git clone git@github.com:<your_fork>/django-loci.git
            cd django_loci
            python setup.py develop
        
        Setup (integrate in an existing django project)
        -----------------------------------------------
        
        First of all, set up your database engine to `one of the spatial databases suppported
        by GeoDjango <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/db-api/#spatial-backends>`_.
        
        Add ``django_loci`` and its dependencies to ``INSTALLED_APPS`` in the following order:
        
        .. code-block:: python
        
            INSTALLED_APPS = [
                # ...
                'django.contrib.gis',
                'django_loci',
                'django.contrib.admin',
                'leaflet',
                'channels'
                # ...
            ]
        
        Configure ``CHANNEL_LAYERS`` according to your needs, a sample configuration can be:
        
        .. code-block:: python
        
            ASGI_APPLICATION = "django_loci.channels.routing.channel_routing"
            CHANNEL_LAYERS = {
                "default": {
                    "BACKEND": "channels.layers.InMemoryChannelLayer",
                },
            }
        
        Now run migrations:
        
        .. code-block:: shell
        
            ./manage.py migrate
        
        Troubleshooting
        ---------------
        
        Common issues and solutions when installing GeoDjango.
        
        Unable to load the SpatiaLite library extension
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        If you get the following exception::
        
            django.core.exceptions.ImproperlyConfigured: Unable to load the SpatiaLite library extension
        
        You need to specify the ``SPATIALITE_LIBRARY_PATH`` in your ``settings.py`` as explained
        in the `django documentation regarding how to install and configure spatialte
        <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/spatialite/>`_.
        
        Issues with other geospatial libraries
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        Please refer to the `geodjango documentation on troubleshooting issues related to
        geospatial libraries <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/#library-environment-settings>`_.
        
        Settings
        --------
        
        ``LOCI_FLOORPLAN_STORAGE``
        ~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        +--------------+-------------------------------------------+
        | **type**:    | ``str``                                   |
        +--------------+-------------------------------------------+
        | **default**: | ``django_loci.storage.OverwriteStorage``  |
        +--------------+-------------------------------------------+
        
        The django file storage class used for uploading floorplan images.
        
        The filestorage can be changed to a different one as long as it has an
        ``upload_to`` class method which will be passed to ``FloorPlan.image.upload_to``.
        
        To understand the details of this statement, take a look at the code of
        `django_loci.storage.OverwriteStorage
        <https://github.com/openwisp/django-loci/blob/master/django_loci/storage.py>`_.
        
        ``DJANGO_LOCI_GEOCODER``
        ~~~~~~~~~~~~~~~~~~~~~~~~
        
        +--------------+-------------+
        | **type**:    | ``str``     |
        +--------------+-------------+
        | **default**: | ``ArcGIS``  |
        +--------------+-------------+
        
        Service used for geocoding and reverse geocoding.
        
        Supported geolocation services:
        
        * ``ArcGIS``
        * ``Nominatim``
        * ``GoogleV3`` (Google Maps v3)
        
        ``DJANGO_LOCI_GEOCODE_STRICT_TEST``
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        +--------------+-----------+
        | **type**:    | ``bool``  |
        +--------------+-----------+
        | **default**: | ``True``  |
        +--------------+-----------+
        
        Indicates whether the system should raise an ``ImproperlyConfigured``
        exception in case geocoding doesn't work when the application is started.
        
        ``DJANGO_LOCI_GEOCODE_FAILURE_DELAY``
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        +--------------+----------+
        | **type**:    | ``int``  |
        +--------------+----------+
        | **default**: | ``1``    |
        +--------------+----------+
        
        Amount of seconds between geocoding retry API calls when geocoding requests fail.
        
        ``DJANGO_LOCI_GEOCODE_RETRIES``
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        +--------------+----------+
        | **type**:    | ``int``  |
        +--------------+----------+
        | **default**: | ``3``    |
        +--------------+----------+
        
        Amount of retry API calls when geocoding requests fail.
        
        ``DJANGO_LOCI_GEOCODE_API_KEY``
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        +--------------+-----------+
        | **type**:    | ``str``   |
        +--------------+-----------+
        | **default**: | ``None``  |
        +--------------+-----------+
        
        API key if required (eg: Google Maps).
        
        Extending django-loci
        ---------------------
        
        *django-loci* provides a set of models and admin classes which can be imported,
        extended and reused by third party apps.
        
        To extend *django-loci*, **you MUST NOT** add it to ``settings.INSTALLED_APPS``,
        but you must create your own app (which goes into ``settings.INSTALLED_APPS``),
        import the base classes of django-loci and add your customizations.
        
        Extending models
        ~~~~~~~~~~~~~~~~
        
        This example provides an example of how to extend the base models of
        *django-loci* by adding a relation to another django model named `Organization`.
        
        .. code-block:: python
        
            # models.py of your app
            from django.db import models
            from django_loci.base.models import (AbstractFloorPlan,
                                                 AbstractLocation,
                                                 AbstractObjectLocation)
        
            # the model ``organizations.Organization`` is omitted for brevity
            # if you are curious to see a real implementation, check out django-organizations
        
        
            class OrganizationMixin(models.Model):
                organization = models.ForeignKey('organizations.Organization')
        
                class Meta:
                    abstract = True
        
        
            class Location(OrganizationMixin, AbstractLocation):
                class Meta(AbstractLocation.Meta):
                    abstract = False
        
                def clean(self):
                    # your own validation logic here...
                    pass
        
        
            class FloorPlan(OrganizationMixin, AbstractFloorPlan):
                location = models.ForeignKey(Location)
        
                class Meta(AbstractFloorPlan.Meta):
                    abstract = False
        
                def clean(self):
                    # your own validation logic here...
                    pass
        
        
            class ObjectLocation(OrganizationMixin, AbstractObjectLocation):
                location = models.ForeignKey(Location, models.PROTECT,
                                             blank=True, null=True)
                floorplan = models.ForeignKey(FloorPlan, models.PROTECT,
                                              blank=True, null=True)
        
                class Meta(AbstractObjectLocation.Meta):
                    abstract = False
        
                def clean(self):
                    # your own validation logic here...
                    pass
        
        Extending the admin
        ~~~~~~~~~~~~~~~~~~~
        
        Following the previous `Organization` example, you can avoid duplicating the admin
        code by importing the base admin classes and registering your models with them.
        
        But first you have to change a few settings in your ``settings.py``, these are needed in
        order to load the admin templates and static files of *django-loci* even if it's not
        listed in ``settings.INSTALLED_APPS``.
        
        Add ``django.forms`` to ``INSTALLED_APPS``, now it should look like the following:
        
        .. code-block:: python
        
            INSTALLED_APPS = [
                # ...
                'django.contrib.gis',
                'django_loci',
                'django.contrib.admin',
                #      ↓
                'django.forms', # <-- add this
                #      ↑
                'leaflet',
                'channels'
                # ...
            ]
        
        Now add ``EXTENDED_APPS`` after ``INSTALLED_APPS``:
        
        .. code-block:: python
        
            INSTALLED_APPS = [
                # ...
            ]
        
            EXTENDED_APPS = ('django_loci',)
        
        Add ``openwisp_utils.staticfiles.DependencyFinder`` to ``STATICFILES_FINDERS``:
        
        .. code-block:: python
        
            STATICFILES_FINDERS = [
                'django.contrib.staticfiles.finders.FileSystemFinder',
                'django.contrib.staticfiles.finders.AppDirectoriesFinder',
                'openwisp_utils.staticfiles.DependencyFinder',
            ]
        
        Add ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES``:
        
        .. code-block:: python
        
            TEMPLATES = [
                {
                    'BACKEND': 'django.template.backends.django.DjangoTemplates',
                    'DIRS': [],
                    'OPTIONS': {
                        'loaders': [
                            'django.template.loaders.filesystem.Loader',
                            'django.template.loaders.app_directories.Loader',
                            # add the following line
                            'openwisp_utils.loaders.DependencyLoader'
                        ],
                        'context_processors': [
                            'django.template.context_processors.debug',
                            'django.template.context_processors.request',
                            'django.contrib.auth.context_processors.auth',
                            'django.contrib.messages.context_processors.messages',
                        ],
                    },
                }
            ]
        
        Last step, add ``FORM_RENDERER``:
        
        .. code-block:: python
        
            FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
        
        Then you can go ahead and create your ``admin.py`` file following the example below:
        
        .. code-block:: python
        
            # admin.py of your app
            from django.contrib import admin
        
            from django_loci.base.admin import (AbstractFloorPlanAdmin, AbstractFloorPlanForm,
                                                AbstractFloorPlanInline, AbstractLocationAdmin,
                                                AbstractLocationForm, AbstractObjectLocationForm,
                                                AbstractObjectLocationInline)
            from django_loci.models import FloorPlan, Location, ObjectLocation
        
        
            class FloorPlanForm(AbstractFloorPlanForm):
                class Meta(AbstractFloorPlanForm.Meta):
                    model = FloorPlan
        
        
            class FloorPlanAdmin(AbstractFloorPlanAdmin):
                form = FloorPlanForm
        
        
            class LocationForm(AbstractLocationForm):
                class Meta(AbstractLocationForm.Meta):
                    model = Location
        
        
            class FloorPlanInline(AbstractFloorPlanInline):
                form = FloorPlanForm
                model = FloorPlan
        
        
            class LocationAdmin(AbstractLocationAdmin):
                form = LocationForm
                inlines = [FloorPlanInline]
        
        
            class ObjectLocationForm(AbstractObjectLocationForm):
                class Meta(AbstractObjectLocationForm.Meta):
                    model = ObjectLocation
        
        
            class ObjectLocationInline(AbstractObjectLocationInline):
                model = ObjectLocation
                form = ObjectLocationForm
        
        
            admin.site.register(FloorPlan, FloorPlanAdmin)
            admin.site.register(Location, LocationAdmin)
        
        Extending channel consumers
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        Extend the channel consumer of django-loci in this way:
        
        .. code-block:: python
        
            from django_loci.channels.base import BaseLocationBroadcast
            from ..models import Location  # your own location model
        
        
            class LocationBroadcast(BaseLocationBroadcast):
                model = Location
        
        Extending AppConfig
        ~~~~~~~~~~~~~~~~~~~
        
        You may want to reuse the ``AppConfig`` class of *django-loci* too:
        
        .. code-block:: python
        
            from django_loci.apps import LociConfig
        
        
            class MyConfig(LociConfig):
                name = 'myapp'
                verbose_name = _('My custom app')
        
                def __setmodels__(self):
                    from .models import Location
                    self.location_model = Location
        
        Installing for development
        --------------------------
        
        Install sqlite:
        
        .. code-block:: shell
        
            sudo apt-get install sqlite3 libsqlite3-dev libsqlite3-mod-spatialite gdal-bin
        
        Install your forked repo:
        
        .. code-block:: shell
        
            git clone git://github.com/<your_fork>/django-loci
            cd django-loci/
            python setup.py develop
        
        Install test requirements:
        
        .. code-block:: shell
        
            pip install -r requirements-test.txt
        
        Create database:
        
        .. code-block:: shell
        
            cd tests/
            ./manage.py migrate
            ./manage.py createsuperuser
        
        Launch development server and SMTP debugging server:
        
        .. code-block:: shell
        
            ./manage.py runserver
        
        You can access the admin interface at http://127.0.0.1:8000/admin/.
        
        Run tests with:
        
        .. code-block:: shell
        
            # pytests is used to test django-channels
            ./runtests.py && pytest
        
        Contributing
        ------------
        
        1. Announce your intentions in the `OpenWISP Mailing List <https://groups.google.com/d/forum/openwisp>`_
        2. Fork this repo and install it
        3. Follow `PEP8, Style Guide for Python Code`_
        4. Write code
        5. Write tests for your code
        6. Ensure all tests pass
        7. Ensure test coverage does not decrease
        8. Document your changes
        9. Send pull request
        
        .. _PEP8, Style Guide for Python Code: http://www.python.org/dev/peps/pep-0008/
        
        Changelog
        ---------
        
        See `CHANGES <https://github.com/openwisp/django-loci/blob/master/CHANGES.rst>`_.
        
        License
        -------
        
        See `LICENSE <https://github.com/openwisp/django-loci/blob/master/LICENSE>`_.
        
Keywords: django,gis
Platform: Platform Independent
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Framework :: Django
Classifier: Programming Language :: Python :: 3
