django-loci
===========
.. image:: https://github.com/openwisp/django-loci/workflows/Django%20Loci%20Build/badge.svg?branch=master
:target: https://github.com/openwisp/django-loci/actions?query=workflow%3A"Django+Loci+Build"
:alt: CI build status
.. image:: https://coveralls.io/repos/openwisp/django-loci/badge.svg
:target: https://coveralls.io/r/openwisp/django-loci
.. image:: https://img.shields.io/librariesio/release/github/openwisp/django-loci
:target: https://libraries.io/github/openwisp/django-loci#repository_dependencies
:alt: Dependency monitoring
.. 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.8
- 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 - 0.4 >=3.6
1.0 >=3.7
1.1 >=3.8
dev >=3.8
=========== ==============
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.asgi.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_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).
System Checks
-------------
``geocoding``
~~~~~~~~~~~~~
Use to check if geocoding is working as expected or not.
Run this checks with:
::
./manage.py check --deploy --tag geocoding
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>`_.
Raw data
{
"_id": null,
"home_page": "http://openwisp.org",
"name": "django-loci",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "django, gis",
"author": "Federico Capoano",
"author_email": "support@openwisp.io",
"download_url": "https://files.pythonhosted.org/packages/28/19/416d4153f311c4a9b996e1534bad2a9f83f0fa8bb5d48402c44e9332d74e/django_loci-1.1.1.tar.gz",
"platform": "Platform Independent",
"description": "django-loci\n===========\n\n.. image:: https://github.com/openwisp/django-loci/workflows/Django%20Loci%20Build/badge.svg?branch=master\n :target: https://github.com/openwisp/django-loci/actions?query=workflow%3A\"Django+Loci+Build\"\n :alt: CI build status\n\n.. image:: https://coveralls.io/repos/openwisp/django-loci/badge.svg\n :target: https://coveralls.io/r/openwisp/django-loci\n\n.. image:: https://img.shields.io/librariesio/release/github/openwisp/django-loci\n :target: https://libraries.io/github/openwisp/django-loci#repository_dependencies\n :alt: Dependency monitoring\n\n.. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square\n :target: https://gitter.im/openwisp/general\n\n.. image:: https://badge.fury.io/py/django-loci.svg\n :target: http://badge.fury.io/py/django-loci\n\n.. image:: https://pepy.tech/badge/django-loci\n :target: https://pepy.tech/project/django-loci\n :alt: downloads\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://pypi.org/project/black/\n :alt: code style: black\n\n----\n\nReusable django-app for storing GIS and indoor coordinates of objects.\n\n.. image:: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/indoor.png\n :target: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/indoor.png\n :alt: Indoor coordinates\n\n.. image:: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/map.png\n :target: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/map.png\n :alt: Map coordinates\n\n.. image:: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/mobile.png\n :target: https://raw.githubusercontent.com/openwisp/django-loci/master/docs/mobile.png\n :alt: Mobile coordinates\n\n----\n\n.. contents:: **Table of Contents**:\n :backlinks: none\n :depth: 3\n\n----\n\nDependencies\n------------\n\n- Python >= 3.8\n- GeoDjango (`see GeoDjango Install Instructions\n <https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/#requirements>`_)\n- One of the databases supported by GeoDjango\n\nCompatibility Table\n-------------------\n\n=========== ==============\ndjango-loci Python version\n0.2 2.7 or >=3.4\n0.3 - 0.4 >=3.6\n1.0 >=3.7\n1.1 >=3.8\ndev >=3.8\n=========== ==============\n\nInstall stable version from pypi\n--------------------------------\n\nInstall from pypi:\n\n.. code-block:: shell\n\n pip install django-loci\n\nInstall development version\n---------------------------\n\nFirst of all, install the dependencies of `GeoDjango\n<https://docs.djangoproject.com/en/2.1/ref/contrib/gis/>`_:\n\n- `Geospatial libraries\n <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/geolibs/>`_\n- `Spatial database\n <https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/spatialite/>`_,\n for development we use Spatialite, a spatial extension of `sqlite\n <https://www.sqlite.org/index.html>`_\n\nInstall tarball:\n\n.. code-block:: shell\n\n pip install https://github.com/openwisp/django-loci/tarball/master\n\nAlternatively you can install via pip using git:\n\n.. code-block:: shell\n\n pip install -e git+git://github.com/openwisp/django-loci#egg=django_loci\n\nIf you want to contribute, install your cloned fork:\n\n.. code-block:: shell\n\n git clone git@github.com:<your_fork>/django-loci.git\n cd django_loci\n python setup.py develop\n\nSetup (integrate in an existing django project)\n-----------------------------------------------\n\nFirst of all, set up your database engine to `one of the spatial databases\nsuppported by GeoDjango\n<https://docs.djangoproject.com/en/2.1/ref/contrib/gis/db-api/#spatial-backends>`_.\n\nAdd ``django_loci`` and its dependencies to ``INSTALLED_APPS`` in the\nfollowing order:\n\n.. code-block:: python\n\n INSTALLED_APPS = [\n # ...\n \"django.contrib.gis\",\n \"django_loci\",\n \"django.contrib.admin\",\n \"leaflet\",\n \"channels\"\n # ...\n ]\n\nConfigure ``CHANNEL_LAYERS`` according to your needs, a sample\nconfiguration can be:\n\n.. code-block:: python\n\n ASGI_APPLICATION = \"django_loci.channels.asgi.channel_routing\"\n CHANNEL_LAYERS = {\n \"default\": {\n \"BACKEND\": \"channels.layers.InMemoryChannelLayer\",\n },\n }\n\nNow run migrations:\n\n.. code-block:: shell\n\n ./manage.py migrate\n\nTroubleshooting\n---------------\n\nCommon issues and solutions when installing GeoDjango.\n\nUnable to load the SpatiaLite library extension\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you get the following exception:\n\n::\n\n django.core.exceptions.ImproperlyConfigured: Unable to load the SpatiaLite library extension\n\nYou need to specify the ``SPATIALITE_LIBRARY_PATH`` in your\n``settings.py`` as explained in the `django documentation regarding how to\ninstall and configure spatialte\n<https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/spatialite/>`_.\n\nIssues with other geospatial libraries\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPlease refer to the `geodjango documentation on troubleshooting issues\nrelated to geospatial libraries\n<https://docs.djangoproject.com/en/2.1/ref/contrib/gis/install/#library-environment-settings>`_.\n\nSettings\n--------\n\n``LOCI_FLOORPLAN_STORAGE``\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n============ ========================================\n**type**: ``str``\n**default**: ``django_loci.storage.OverwriteStorage``\n============ ========================================\n\nThe django file storage class used for uploading floorplan images.\n\nThe filestorage can be changed to a different one as long as it has an\n``upload_to`` class method which will be passed to\n``FloorPlan.image.upload_to``.\n\nTo understand the details of this statement, take a look at the code of\n`django_loci.storage.OverwriteStorage\n<https://github.com/openwisp/django-loci/blob/master/django_loci/storage.py>`_.\n\n``DJANGO_LOCI_GEOCODER``\n~~~~~~~~~~~~~~~~~~~~~~~~\n\n============ ==========\n**type**: ``str``\n**default**: ``ArcGIS``\n============ ==========\n\nService used for geocoding and reverse geocoding.\n\nSupported geolocation services:\n\n- ``ArcGIS``\n- ``Nominatim``\n- ``GoogleV3`` (Google Maps v3)\n\n``DJANGO_LOCI_GEOCODE_FAILURE_DELAY``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n============ =======\n**type**: ``int``\n**default**: ``1``\n============ =======\n\nAmount of seconds between geocoding retry API calls when geocoding\nrequests fail.\n\n``DJANGO_LOCI_GEOCODE_RETRIES``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n============ =======\n**type**: ``int``\n**default**: ``3``\n============ =======\n\nAmount of retry API calls when geocoding requests fail.\n\n``DJANGO_LOCI_GEOCODE_API_KEY``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n============ ========\n**type**: ``str``\n**default**: ``None``\n============ ========\n\nAPI key if required (eg: Google Maps).\n\nSystem Checks\n-------------\n\n``geocoding``\n~~~~~~~~~~~~~\n\nUse to check if geocoding is working as expected or not.\n\nRun this checks with:\n\n::\n\n ./manage.py check --deploy --tag geocoding\n\nExtending django-loci\n---------------------\n\n*django-loci* provides a set of models and admin classes which can be\nimported, extended and reused by third party apps.\n\nTo extend *django-loci*, **you MUST NOT** add it to\n``settings.INSTALLED_APPS``, but you must create your own app (which goes\ninto ``settings.INSTALLED_APPS``), import the base classes of django-loci\nand add your customizations.\n\nExtending models\n~~~~~~~~~~~~~~~~\n\nThis example provides an example of how to extend the base models of\n*django-loci* by adding a relation to another django model named\n`Organization`.\n\n.. code-block:: python\n\n # models.py of your app\n from django.db import models\n from django_loci.base.models import (\n AbstractFloorPlan,\n AbstractLocation,\n AbstractObjectLocation,\n )\n\n # the model ``organizations.Organization`` is omitted for brevity\n # if you are curious to see a real implementation, check out django-organizations\n\n\n class OrganizationMixin(models.Model):\n organization = models.ForeignKey(\"organizations.Organization\")\n\n class Meta:\n abstract = True\n\n\n class Location(OrganizationMixin, AbstractLocation):\n class Meta(AbstractLocation.Meta):\n abstract = False\n\n def clean(self):\n # your own validation logic here...\n pass\n\n\n class FloorPlan(OrganizationMixin, AbstractFloorPlan):\n location = models.ForeignKey(Location)\n\n class Meta(AbstractFloorPlan.Meta):\n abstract = False\n\n def clean(self):\n # your own validation logic here...\n pass\n\n\n class ObjectLocation(OrganizationMixin, AbstractObjectLocation):\n location = models.ForeignKey(\n Location, models.PROTECT, blank=True, null=True\n )\n floorplan = models.ForeignKey(\n FloorPlan, models.PROTECT, blank=True, null=True\n )\n\n class Meta(AbstractObjectLocation.Meta):\n abstract = False\n\n def clean(self):\n # your own validation logic here...\n pass\n\nExtending the admin\n~~~~~~~~~~~~~~~~~~~\n\nFollowing the previous `Organization` example, you can avoid duplicating\nthe admin code by importing the base admin classes and registering your\nmodels with them.\n\nBut first you have to change a few settings in your ``settings.py``, these\nare needed in order to load the admin templates and static files of\n*django-loci* even if it's not listed in ``settings.INSTALLED_APPS``.\n\nAdd ``django.forms`` to ``INSTALLED_APPS``, now it should look like the\nfollowing:\n\n.. code-block:: python\n\n INSTALLED_APPS = [\n # ...\n \"django.contrib.gis\",\n \"django_loci\",\n \"django.contrib.admin\",\n # \u2193\n \"django.forms\", # <-- add this\n # \u2191\n \"leaflet\",\n \"channels\"\n # ...\n ]\n\nNow add ``EXTENDED_APPS`` after ``INSTALLED_APPS``:\n\n.. code-block:: python\n\n INSTALLED_APPS = [\n # ...\n ]\n\n EXTENDED_APPS = (\"django_loci\",)\n\nAdd ``openwisp_utils.staticfiles.DependencyFinder`` to\n``STATICFILES_FINDERS``:\n\n.. code-block:: python\n\n STATICFILES_FINDERS = [\n \"django.contrib.staticfiles.finders.FileSystemFinder\",\n \"django.contrib.staticfiles.finders.AppDirectoriesFinder\",\n \"openwisp_utils.staticfiles.DependencyFinder\",\n ]\n\nAdd ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES``:\n\n.. code-block:: python\n\n TEMPLATES = [\n {\n \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n \"DIRS\": [],\n \"OPTIONS\": {\n \"loaders\": [\n \"django.template.loaders.filesystem.Loader\",\n \"django.template.loaders.app_directories.Loader\",\n # add the following line\n \"openwisp_utils.loaders.DependencyLoader\",\n ],\n \"context_processors\": [\n \"django.template.context_processors.debug\",\n \"django.template.context_processors.request\",\n \"django.contrib.auth.context_processors.auth\",\n \"django.contrib.messages.context_processors.messages\",\n ],\n },\n }\n ]\n\nLast step, add ``FORM_RENDERER``:\n\n.. code-block:: python\n\n FORM_RENDERER = \"django.forms.renderers.TemplatesSetting\"\n\nThen you can go ahead and create your ``admin.py`` file following the\nexample below:\n\n.. code-block:: python\n\n # admin.py of your app\n from django.contrib import admin\n\n from django_loci.base.admin import (\n AbstractFloorPlanAdmin,\n AbstractFloorPlanForm,\n AbstractFloorPlanInline,\n AbstractLocationAdmin,\n AbstractLocationForm,\n AbstractObjectLocationForm,\n AbstractObjectLocationInline,\n )\n from django_loci.models import FloorPlan, Location, ObjectLocation\n\n\n class FloorPlanForm(AbstractFloorPlanForm):\n class Meta(AbstractFloorPlanForm.Meta):\n model = FloorPlan\n\n\n class FloorPlanAdmin(AbstractFloorPlanAdmin):\n form = FloorPlanForm\n\n\n class LocationForm(AbstractLocationForm):\n class Meta(AbstractLocationForm.Meta):\n model = Location\n\n\n class FloorPlanInline(AbstractFloorPlanInline):\n form = FloorPlanForm\n model = FloorPlan\n\n\n class LocationAdmin(AbstractLocationAdmin):\n form = LocationForm\n inlines = [FloorPlanInline]\n\n\n class ObjectLocationForm(AbstractObjectLocationForm):\n class Meta(AbstractObjectLocationForm.Meta):\n model = ObjectLocation\n\n\n class ObjectLocationInline(AbstractObjectLocationInline):\n model = ObjectLocation\n form = ObjectLocationForm\n\n\n admin.site.register(FloorPlan, FloorPlanAdmin)\n admin.site.register(Location, LocationAdmin)\n\nExtending channel consumers\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nExtend the channel consumer of django-loci in this way:\n\n.. code-block:: python\n\n from django_loci.channels.base import BaseLocationBroadcast\n from ..models import Location # your own location model\n\n\n class LocationBroadcast(BaseLocationBroadcast):\n model = Location\n\nExtending AppConfig\n~~~~~~~~~~~~~~~~~~~\n\nYou may want to reuse the ``AppConfig`` class of *django-loci* too:\n\n.. code-block:: python\n\n from django_loci.apps import LociConfig\n\n\n class MyConfig(LociConfig):\n name = \"myapp\"\n verbose_name = _(\"My custom app\")\n\n def __setmodels__(self):\n from .models import Location\n\n self.location_model = Location\n\nInstalling for development\n--------------------------\n\nInstall sqlite:\n\n.. code-block:: shell\n\n sudo apt-get install sqlite3 libsqlite3-dev libsqlite3-mod-spatialite gdal-bin\n\nInstall your forked repo:\n\n.. code-block:: shell\n\n git clone git://github.com/<your_fork>/django-loci\n cd django-loci/\n python setup.py develop\n\nInstall test requirements:\n\n.. code-block:: shell\n\n pip install -r requirements-test.txt\n\nCreate database:\n\n.. code-block:: shell\n\n cd tests/\n ./manage.py migrate\n ./manage.py createsuperuser\n\nLaunch development server and SMTP debugging server:\n\n.. code-block:: shell\n\n ./manage.py runserver\n\nYou can access the admin interface at http://127.0.0.1:8000/admin/.\n\nRun tests with:\n\n.. code-block:: shell\n\n # pytests is used to test django-channels\n ./runtests.py && pytest\n\nContributing\n------------\n\n1. Announce your intentions in the `OpenWISP Mailing List\n <https://groups.google.com/d/forum/openwisp>`_\n2. Fork this repo and install it\n3. Follow `PEP8, Style Guide for Python Code`_\n4. Write code\n5. Write tests for your code\n6. Ensure all tests pass\n7. Ensure test coverage does not decrease\n8. Document your changes\n9. Send pull request\n\n.. _pep8, style guide for python code: http://www.python.org/dev/peps/pep-0008/\n\nChangelog\n---------\n\nSee `CHANGES\n<https://github.com/openwisp/django-loci/blob/master/CHANGES.rst>`_.\n\nLicense\n-------\n\nSee `LICENSE\n<https://github.com/openwisp/django-loci/blob/master/LICENSE>`_.\n",
"bugtrack_url": null,
"license": "BSD",
"summary": "Reusable django-app for outdoor and indoor mapping",
"version": "1.1.1",
"project_urls": {
"Download": "https://github.com/openwisp/django-loci/releases",
"Homepage": "http://openwisp.org"
},
"split_keywords": [
"django",
" gis"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "15c83149a6c59abfe00fce4daf5cf6764137931c2c5c59eab2427dfa8c65f930",
"md5": "32cbb1e7f8a33e7afa1de8491108ade8",
"sha256": "74ace884968612ffe79ff2b417847a2f4971b5a08467f2a9cd1d9bf501542faf"
},
"downloads": -1,
"filename": "django_loci-1.1.1-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "32cbb1e7f8a33e7afa1de8491108ade8",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 48203,
"upload_time": "2024-11-20T19:21:27",
"upload_time_iso_8601": "2024-11-20T19:21:27.782758Z",
"url": "https://files.pythonhosted.org/packages/15/c8/3149a6c59abfe00fce4daf5cf6764137931c2c5c59eab2427dfa8c65f930/django_loci-1.1.1-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2819416d4153f311c4a9b996e1534bad2a9f83f0fa8bb5d48402c44e9332d74e",
"md5": "84eebc3522bcb7071114f3d56ea84048",
"sha256": "fb95c335f3b0d2f6c71f6eac6f9aabfa1182bff2a25d6bf171b927a863509455"
},
"downloads": -1,
"filename": "django_loci-1.1.1.tar.gz",
"has_sig": false,
"md5_digest": "84eebc3522bcb7071114f3d56ea84048",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 42793,
"upload_time": "2024-11-20T19:21:29",
"upload_time_iso_8601": "2024-11-20T19:21:29.940798Z",
"url": "https://files.pythonhosted.org/packages/28/19/416d4153f311c4a9b996e1534bad2a9f83f0fa8bb5d48402c44e9332d74e/django_loci-1.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-20 19:21:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "openwisp",
"github_project": "django-loci",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "django-loci"
}