Package: django-loci
Reusable django-app for storing GIS and indoor coordinates of objects.Table of Contents:DependenciesCompatibility TableInstall stable version from pypiInstall development versionSetup (integrate in an existing django project)TroubleshootingUnable to load the SpatiaLite library extensionIssues with other geospatial librariesSettingsLOCI_FLOORPLAN_STORAGEDJANGO_LOCI_GEOCODERDJANGO_LOCI_GEOCODE_FAILURE_DELAYDJANGO_LOCI_GEOCODE_RETRIESDJANGO_LOCI_GEOCODE_API_KEYSystem ChecksExtending django-lociExtending modelsExtending the adminExtending channel consumersExtending AppConfigInstalling for developmentContributingChangelogLicenseDependenciesPython >= 3.7GeoDjango (see GeoDjango Install Instructions)One of the databases supported by GeoDjangoCompatibility Tabledjango-lociPython version0.22.7 or >=3.40.3 - 0.4>=3.60.5>=3.7Install stable version from pypiInstall from pypi:pipinstalldjango-lociInstall development versionFirst of all, install the dependencies ofGeoDjango:Geospatial librariesSpatial database,
for development we use Spatialite, a spatial extension ofsqliteInstall tarball:pipinstallhttps://github.com/openwisp/django-loci/tarball/masterAlternatively you can install via pip using git:pipinstall-egit+git://github.com/openwisp/django-loci#egg=django_lociIf you want to contribute, install your cloned fork:gitclonegit@github.com:<your_fork>/django-loci.gitcddjango_locipythonsetup.pydevelopSetup (integrate in an existing django project)First of all, set up your database engine toone of the spatial databases suppported
by GeoDjango.Adddjango_lociand its dependencies toINSTALLED_APPSin the following order:INSTALLED_APPS=[# ...'django.contrib.gis','django_loci','django.contrib.admin','leaflet','channels'# ...]ConfigureCHANNEL_LAYERSaccording to your needs, a sample configuration can be:ASGI_APPLICATION="django_loci.channels.routing.channel_routing"CHANNEL_LAYERS={"default":{"BACKEND":"channels.layers.InMemoryChannelLayer",},}Now run migrations:./manage.pymigrateTroubleshootingCommon issues and solutions when installing GeoDjango.Unable to load the SpatiaLite library extensionIf you get the following exception:django.core.exceptions.ImproperlyConfigured: Unable to load the SpatiaLite library extensionYou need to specify theSPATIALITE_LIBRARY_PATHin yoursettings.pyas explained
in thedjango documentation regarding how to install and configure spatialte.Issues with other geospatial librariesPlease refer to thegeodjango documentation on troubleshooting issues related to
geospatial libraries.SettingsLOCI_FLOORPLAN_STORAGEtype:strdefault:django_loci.storage.OverwriteStorageThe django file storage class used for uploading floorplan images.The filestorage can be changed to a different one as long as it has anupload_toclass method which will be passed toFloorPlan.image.upload_to.To understand the details of this statement, take a look at the code ofdjango_loci.storage.OverwriteStorage.DJANGO_LOCI_GEOCODERtype:strdefault:ArcGISService used for geocoding and reverse geocoding.Supported geolocation services:ArcGISNominatimGoogleV3(Google Maps v3)DJANGO_LOCI_GEOCODE_FAILURE_DELAYtype:intdefault:1Amount of seconds between geocoding retry API calls when geocoding requests fail.DJANGO_LOCI_GEOCODE_RETRIEStype:intdefault:3Amount of retry API calls when geocoding requests fail.DJANGO_LOCI_GEOCODE_API_KEYtype:strdefault:NoneAPI key if required (eg: Google Maps).System ChecksgeocodingUse to check if geocoding is working as expected or not.Run this checks with:./manage.py check --deploy --tag geocodingExtending django-locidjango-lociprovides a set of models and admin classes which can be imported,
extended and reused by third party apps.To extenddjango-loci,you MUST NOTadd it tosettings.INSTALLED_APPS,
but you must create your own app (which goes intosettings.INSTALLED_APPS),
import the base classes of django-loci and add your customizations.Extending modelsThis example provides an example of how to extend the base models ofdjango-lociby adding a relation to another django model namedOrganization.# models.py of your appfromdjango.dbimportmodelsfromdjango_loci.base.modelsimport(AbstractFloorPlan,AbstractLocation,AbstractObjectLocation)# the model ``organizations.Organization`` is omitted for brevity# if you are curious to see a real implementation, check out django-organizationsclassOrganizationMixin(models.Model):organization=models.ForeignKey('organizations.Organization')classMeta:abstract=TrueclassLocation(OrganizationMixin,AbstractLocation):classMeta(AbstractLocation.Meta):abstract=Falsedefclean(self):# your own validation logic here...passclassFloorPlan(OrganizationMixin,AbstractFloorPlan):location=models.ForeignKey(Location)classMeta(AbstractFloorPlan.Meta):abstract=Falsedefclean(self):# your own validation logic here...passclassObjectLocation(OrganizationMixin,AbstractObjectLocation):location=models.ForeignKey(Location,models.PROTECT,blank=True,null=True)floorplan=models.ForeignKey(FloorPlan,models.PROTECT,blank=True,null=True)classMeta(AbstractObjectLocation.Meta):abstract=Falsedefclean(self):# your own validation logic here...passExtending the adminFollowing the previousOrganizationexample, 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 yoursettings.py, these are needed in
order to load the admin templates and static files ofdjango-locieven if it’s not
listed insettings.INSTALLED_APPS.Adddjango.formstoINSTALLED_APPS, now it should look like the following:INSTALLED_APPS=[# ...'django.contrib.gis','django_loci','django.contrib.admin',#      ↓'django.forms',# <-- add this#      ↑'leaflet','channels'# ...]Now addEXTENDED_APPSafterINSTALLED_APPS:INSTALLED_APPS=[# ...]EXTENDED_APPS=('django_loci',)Addopenwisp_utils.staticfiles.DependencyFindertoSTATICFILES_FINDERS:STATICFILES_FINDERS=['django.contrib.staticfiles.finders.FileSystemFinder','django.contrib.staticfiles.finders.AppDirectoriesFinder','openwisp_utils.staticfiles.DependencyFinder',]Addopenwisp_utils.loaders.DependencyLoadertoTEMPLATES: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, addFORM_RENDERER:FORM_RENDERER='django.forms.renderers.TemplatesSetting'Then you can go ahead and create youradmin.pyfile following the example below:# admin.py of your appfromdjango.contribimportadminfromdjango_loci.base.adminimport(AbstractFloorPlanAdmin,AbstractFloorPlanForm,AbstractFloorPlanInline,AbstractLocationAdmin,AbstractLocationForm,AbstractObjectLocationForm,AbstractObjectLocationInline)fromdjango_loci.modelsimportFloorPlan,Location,ObjectLocationclassFloorPlanForm(AbstractFloorPlanForm):classMeta(AbstractFloorPlanForm.Meta):model=FloorPlanclassFloorPlanAdmin(AbstractFloorPlanAdmin):form=FloorPlanFormclassLocationForm(AbstractLocationForm):classMeta(AbstractLocationForm.Meta):model=LocationclassFloorPlanInline(AbstractFloorPlanInline):form=FloorPlanFormmodel=FloorPlanclassLocationAdmin(AbstractLocationAdmin):form=LocationForminlines=[FloorPlanInline]classObjectLocationForm(AbstractObjectLocationForm):classMeta(AbstractObjectLocationForm.Meta):model=ObjectLocationclassObjectLocationInline(AbstractObjectLocationInline):model=ObjectLocationform=ObjectLocationFormadmin.site.register(FloorPlan,FloorPlanAdmin)admin.site.register(Location,LocationAdmin)Extending channel consumersExtend the channel consumer of django-loci in this way:fromdjango_loci.channels.baseimportBaseLocationBroadcastfrom..modelsimportLocation# your own location modelclassLocationBroadcast(BaseLocationBroadcast):model=LocationExtending AppConfigYou may want to reuse theAppConfigclass ofdjango-locitoo:fromdjango_loci.appsimportLociConfigclassMyConfig(LociConfig):name='myapp'verbose_name=_('My custom app')def__setmodels__(self):from.modelsimportLocationself.location_model=LocationInstalling for developmentInstall sqlite:sudoapt-getinstallsqlite3libsqlite3-devlibsqlite3-mod-spatialitegdal-binInstall your forked repo:gitclonegit://github.com/<your_fork>/django-locicddjango-loci/pythonsetup.pydevelopInstall test requirements:pipinstall-rrequirements-test.txtCreate database:cdtests/./manage.pymigrate./manage.pycreatesuperuserLaunch development server and SMTP debugging server:./manage.pyrunserverYou can access the admin interface athttp://127.0.0.1:8000/admin/.Run tests with:# pytests is used to test django-channels./runtests.py&&pytestContributingAnnounce your intentions in theOpenWISP Mailing ListFork this repo and install itFollowPEP8, Style Guide for Python CodeWrite codeWrite tests for your codeEnsure all tests passEnsure test coverage does not decreaseDocument your changesSend pull requestChangelogSeeCHANGES.LicenseSeeLICENSE.