Package: django-mapbox-location-field
django-mapbox-location-fieldSimple in uselocation model and form fieldwithMapInput widgetfor picking some location. Usesmapbox gl js, flexible map provider API. Fully compatible with bootstrap framework.Table of contentsWhy this?Live demoCompatibilityVersions >1.4.0 noteInstallationConfigurationUsagePLAIN (non-spatial) dbSPATIAL dbCustomizationmap_attrsbootstrapAdmin interface usageAddressAutoHiddenFieldMultiple fields usageTroubleshootingTechnologiesWhy this?I was searching for some django location field which uses mapbox to use it in my project. However, I didn't find anything which suited my needs in 100% and that's why I created this simple django app. My philosophy was simplicity, but I wanted to create complete solution for picking location.Feel free to open issues, make pull request and request some features or instructions. Let me know if you think it is not flexible enough.Live demoCurious how it works and looks like? See live demo onhttps://django-mapbox-location-field.herokuapp.comDemo app usesdjango-bootstrap4for a little better looking form fields.You can also use it as a code example, because it is available onmy github.CompatibilityBreaking changesSincev2.0.0package supports onlyDjangoversions3.xand4.xand its relevantPythonversions, due to breaking changes in Django api.
For Django2.xand1.x, you can use version1.7.4and below and it should work relatively well, but newest upgrades will not be applied.Package automatically tested on Github Actions:Django4.0.3and3.2.12Python3.8,3.9,3.10Browser supportdjango-mapbox-location-field support all browsers, which are supported by mapbox gl js. Read morehereDatabases supportIt should work with everyspatialandplain(non-spatial) database, that works with django and geodjango.Versions >1.4.0Since version 1.4.0 the order of coordinates convention has been changed. Now the order islongitude, latitude. This change has been caused by support for spatial databases. Nevertheless, more user-friendly is orderlatitude, longitude(Google Maps uses it). That's why coordinates are falsely swapped in frontend and then after POST request in form field are swapped back intolongitude, latitudeorder and saved to database.My conclusion is that the location is falsely swapped in frontend and if you create location without our custom form field or just operate on a raw model in the backend, you will have to use thelongitude, latitudeorder.Versions before 1.4.0 always useslatitude, longitudeorder.InstallationUsing pip:pip install django-mapbox-location-fieldConfigurationAdd"mapbox_location_field"toINSTALLED_APPSin your settings fileINSTALLED_APPS+=("mapbox_location_field",)DefineMAPBOX_KEYin your settings file. This is vulnerable information which has to be passed to frontend, so it can be easily accessed by user. To ensure your safety, I would recommend usingurl restrictionsandpublic scopes. More information on linked websites.MAPBOX_KEY="pk.eyJ1IjoibWlnaHR5c2hhcmt5IiwiYSI6ImNqd2duaW4wMzBhcWI0M3F1MTRvbHB0dWcifQ.1sDAD43q0ktK1Sr374xGfw"PS. This above is only example access token. You have to paste here yours.UsagePLAIN DATABASEJust create some model with LocationField.fromdjango.dbimportmodelsfrommapbox_location_field.modelsimportLocationFieldclassSomeLocationModel(models.Model):location=LocationField()SPATIAL DATABASEJust create some model with SpatialLocationField.fromdjango.dbimportmodelsfrommapbox_location_field.spatial.modelsimportSpatialLocationFieldclassSomeLocationModel(models.Model):location=SpatialLocationField()Create ModelFormfromdjangoimportformsfrom.modelsimportLocationclassLocationForm(forms.ModelForm):classMeta:model=Locationfields="__all__"Of course, you can also use CreateView, UpdateView or build Form yourself withmapbox_location_field.forms.LocationFieldormapbox_location_field.spatial.forms.SpatialLocationFieldThen just use it in html view. It can't be simpler!Paste this in your html head:{%loadmapbox_location_field_tags%}{%location_field_includes%}{%include_jquery%}And this in your body:<form method="post">{%csrf_token%}{{form}}<input type="submit" value="submit"></form>{{form.media}}Your form is ready! Start your website and see how it looks. If you want to change something look to thecustomizationsection.CustomizationIn order to change few things you have to usemap_attrsdictionary.Defaultmap_attrslooks like this:default_map_attrs={"style":"mapbox://styles/mapbox/outdoors-v11","zoom":13,"center":[17.031645,51.106715],"cursor_style":'pointer',"marker_color":"red","rotate":False,"geocoder":True,"fullscreen_button":True,"navigation_buttons":True,"track_location_button":True,"readonly":True,"placeholder":"Pick a location on map below","language":"auto","message_404":"undefined address",}To change some values, just pass it when you create model.fromdjango.dbimportmodelsfrommapbox_location_field.modelsimportLocationFieldclassLocation(models.Model):location=LocationField(map_attrs={"center":[0,0],"marker_color":"blue"})map_attrsstyle -<string>, mapbox style url. Read morehere.zoom -<int>, map's zoom. Read morehere.center -<list>or<tuple>of<float>s, defaults map's center point in [latitude,longitude]cursor_style -<string>, css cursor style. Read morehere.marker_color -<string>css color property. Read morehereandhere.rotate -<bool>, whether you can rotate the map with right mouse click or not.geocoder -<bool>, whether geocoder searcher is showed or not.fullscreen_button -<bool>, whether fullscreen button is showed or not.navigation_buttons -<bool>, whether navigation buttons are showed or not.track_location_button -<bool>, whether show my location button is showed or not.readonly -<bool>, whether user can type location in text inputplaceholder -<string>, text input's placeholderid -<string>, unique id for the field, when you are using multiple fields (See more inthis section). When you use only one field, you don't have to define it, because default value is taken.language -<string>, language of an address returned from geocoding queries. Default is"auto"- which lets mapbox gl js determine the language (usually browser language if available). Hovewer, you can specify it in case of need. Check outlanguage coverage section in mapbox docsto see available options of this field.message_404 -<string>, string used when no address is returned from geocoding query (e.q. marker on the ocean area). Default is simple:"undefined address"bootstrapMapInput widget is fully compatible with bootstrap library. I can even recommend using it withdjango-bootstrap4ordjango-crispy-forms.Admin interface usageFirst create some model with location field like inusage section.Then register it in admin interface like this:Plain:fromdjango.contribimportadminfrom.modelsimportSomeLocationModelfrommapbox_location_field.adminimportMapAdminadmin.site.register(SomeLocationModel,MapAdmin)Spatial:fromdjango.contribimportadminfrom.modelsimportSomeLocationModelfrommapbox_location_field.spatial.adminimportSpatialMapAdminadmin.site.register(SomeLocationModel,SpatialMapAdmin)Admin customization:Sincev1.7.0admin customization should work out of the box, automatically using themap_attrsfrom model definition.AddressAutoHiddenFieldAddressAutoHiddenField is a field for storing address. It uses AddressAutoHiddenInput which is hidden and when you place your marker on the map, automatically fill itself with proper address.In order to use it just add it to your model. Something like this:classLocation(models.Model):location=LocationField()address=AddressAutoHiddenField()Multiple fields usageSince version 1.6.0, it is now possible to use multiple LocationFields (or forms or widgets) as well as multiple AutoHiddenAddressFields. All you have to do is define uniqueidinmap_attrs:location1=LocationField(map_attrs={"id":"unique_id_1"})location2=LocationField(map_attrs={"id":"unique_id_2"})Then you can also use these ids asmap_idin your AutoHiddenAddressFields:address1=AddressAutoHiddenField(map_id="unique_id_1")address2=AddressAutoHiddenField(map_id="unique_id_2")TroubleshootingUsage of the plain field's value in javascript (Issue #21)In case of the plain field, the python representation of coordinates is atuple. And e.g. Mapbox requires ajavascript's arraywhen placing a marker on a map, which has identical syntax asPython's list. In order to make the transformation as easy as possible, sincev1.6.4you can use a special filter or tag (
choose your preferred way){%loadmapbox_location_field_tags%}<script>var lngLatWithFilter ={{object.location|tuple_to_array}};var lngLatWithTag ={%tuple_to_arrayobject.location%};// These are just two ways, which give the same result// Now you can use one of this variables as an array</script>Address field's width and coordinates order convetions (Issue #30)Stackoverflow questions:Unable to show the data in django-mapbox-location-field DjangoTechnologiesDjangoMapbox GL JSjQueryHTML and CSS