Skip to main content

location field with MapInput widget for picking some location

Project description

django-mapbox-location-field

Build status Coverage Status PyPI PyPI - Downloads


Simple in use location model and form field with MapInput widget for picking some location. Uses mapbox gl js, flexible map provider API. Fully compatible with bootstrap framework.


Table of contents

Why 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.

PyPi's funny statistics (downloads etc): https://pypistats.org/packages/django-mapbox-location-field

Live demo

Curious how it works and looks like? See live demo on https://dj-map-loc-field-demo.kowalinski.dev
Demo app uses django-bootstrap4 for a little better looking form fields.
You can also use it as a code example, because it is available on my github.

Compatibility

Breaking changes

Since v2.0.0 package supports only Django versions 3.x and 4.x and its relevant Python versions, due to breaking changes in Django api. For Django 2.x and 1.x, you can use version 1.7.4 and below and it should work relatively well, but newest upgrades will not be applied.

Package automatically tested on Github Actions:

  • Django 5.0.3, 4.2 and 3.2.12
  • Python 3.10, 3.11, 3.12

Browser support

django-mapbox-location-field support all browsers, which are supported by mapbox gl js. Read more here

Databases support

It should work with every spatial and plain (non-spatial) database, that works with django and geodjango.

Versions >1.4.0

Since version 1.4.0 the order of coordinates convention has been changed. Now the order is longitude, latitude. This change has been caused by support for spatial databases. Nevertheless, more user-friendly is order latitude, 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 into longitude, latitude order 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 the longitude, latitude order.
Versions before 1.4.0 always uses latitude, longitude order.

Installation

Using pip:
pip install django-mapbox-location-field

Configuration

  • Add "mapbox_location_field" to INSTALLED_APPS in your settings file
INSTALLED_APPS += ("mapbox_location_field",)  
  • Define MAPBOX_KEY in 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 using url restrictions and public 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.

Usage

PLAIN DATABASE

  • Just create some model with LocationField.
from django.db import models  
from mapbox_location_field.models import LocationField  
class SomeLocationModel(models.Model):  
    location = LocationField()  

SPATIAL DATABASE

  • Just create some model with SpatialLocationField.
 from django.db import models 
 from mapbox_location_field.spatial.models import SpatialLocationField  
 class SomeLocationModel(models.Model):  
	 location = SpatialLocationField()    
  • Create ModelForm
from django import forms 
from .models import SomeLocationModel  
class LocationForm(forms.ModelForm):  
    class Meta:  
   	 model = SomeLocationModel 
   	 fields = "__all__" 

Of course, you can also use CreateView, UpdateView or build Form yourself with mapbox_location_field.forms.LocationField or mapbox_location_field.spatial.forms.SpatialLocationField

  • Then just use it in html view. It can't be simpler!
    Paste this in your html head:
 {% load mapbox_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 the customization section.

Customization

In order to change few things you have to use map_attrs dictionary.
Default map_attrs looks 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.

from django.db import models  
from mapbox_location_field.models import LocationField  
  
class SomeLocationModel(models.Model):  
    location = LocationField(map_attrs={"center": [0,0], "marker_color": "blue"})  

map_attrs

  • style - <string>, mapbox style url. Read more here.
  • zoom - <int>, map's zoom. Read more here.
  • center - <list> or <tuple> of <float>s, defaults map's center point in [latitude, longitude]
  • cursor_style - <string>, css cursor style. Read more here.
  • marker_color - <string> css color property. Read more here and here.
  • 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 input
  • placeholder - <string>, text input's placeholder
  • id - <string>, unique id for the field, when you are using multiple fields (See more in this 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 out language coverage section in mapbox docs to 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"

bootstrap

MapInput widget is fully compatible with bootstrap library. I can even recommend using it with django-bootstrap4 or django-crispy-forms.

Admin interface usage

First create some model with location field like in usage section.
Then register it in admin interface like this:

  • Plain:

from django.contrib import admin   
from .models import SomeLocationModel   
from mapbox_location_field.admin import MapAdmin   
  
admin.site.register(SomeLocationModel, MapAdmin)  
  • Spatial:

from django.contrib import admin  
from .models import SomeLocationModel  
from mapbox_location_field.spatial.admin import SpatialMapAdmin  
  
admin.site.register(SomeLocationModel, SpatialMapAdmin)  
  • Admin customization:

Since v1.7.0 admin customization should work out of the box, automatically using the map_attrs from model definition.

AddressAutoHiddenField

AddressAutoHiddenField 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:

class SomeLocationModel(models.Model):  
    location = LocationField()  
    address = AddressAutoHiddenField()  

Multiple fields usage

Since 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 unique id in map_attrs:

location1 = LocationField(map_attrs={"id": "unique_id_1"})  
location2 = LocationField(map_attrs={"id": "unique_id_2"})  

Then you can also use these ids as map_id in your AutoHiddenAddressFields:

address1 = AddressAutoHiddenField(map_id="unique_id_1")  
address2 = AddressAutoHiddenField(map_id="unique_id_2")  

Troubleshooting

Technologies

  • Django
  • Mapbox GL JS
  • jQuery
  • HTML and CSS

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-mapbox-location-field-2.1.0.tar.gz (18.5 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page