Skip to main content

Overview

Django Location Field provides a location field and widget that displays an interactive map in your Django admin. Unfold’s integration ensures the map widget is properly styled and integrated with your admin interface.
Location fields make it easy to store geographic coordinates (latitude/longitude) and display them on an interactive map for intuitive location selection.

Installation

1

Install django-location-field

Install the package using pip:
pip install django-location-field
2

Add to INSTALLED_APPS

Add both unfold.contrib.location_field and location_field to your settings. Order matters:
settings.py
INSTALLED_APPS = [
    "unfold",
    "unfold.contrib.location_field",  # Before location_field
    
    "django.contrib.admin",
    # ...
    
    "location_field",
]

Basic Usage

Model with Location Field

models.py
from django.db import models
from location_field.models.plain import PlainLocationField

class Venue(models.Model):
    name = models.CharField(max_length=200)
    address = models.TextField()
    location = PlainLocationField(
        based_fields=["address"],
        zoom=7
    )
    
    def __str__(self):
        return self.name

Admin Configuration

Use Unfold’s location widget in your admin:
admin.py
from django.contrib import admin
from django import forms
from unfold.admin import ModelAdmin
from unfold.widgets import UnfoldAdminLocationWidget
from .models import Venue

class VenueAdminForm(forms.ModelForm):
    class Meta:
        model = Venue
        fields = "__all__"
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["location"].widget = UnfoldAdminLocationWidget(
            based_fields=["address"],
            zoom=7
        )

@admin.register(Venue)
class VenueAdmin(ModelAdmin):
    form = VenueAdminForm
    list_display = ["name", "address", "location"]
    search_fields = ["name", "address"]

Widget Options

Based Fields

Automatically geocode based on other fields:
self.fields["location"].widget = UnfoldAdminLocationWidget(
    based_fields=["city", "address"],  # Use city and address for geocoding
    zoom=12
)
When users fill in the city and address fields, the map automatically updates to show the location.

Zoom Level

Set the default zoom level:
self.fields["location"].widget = UnfoldAdminLocationWidget(
    based_fields=["address"],
    zoom=15  # Higher number = more zoomed in
)

Suffix

Add a custom suffix to the widget:
self.fields["location"].widget = UnfoldAdminLocationWidget(
    based_fields=["address"],
    suffix="📍"  # Custom marker
)

Field Types

Django Location Field provides different field types:

PlainLocationField

Stores coordinates as a string:
models.py
from location_field.models.plain import PlainLocationField

class Store(models.Model):
    location = PlainLocationField(based_fields=["address"], zoom=7)
    # Stored as: "40.7128,-74.0060"

SpatialLocationField

Uses GeoDjango for spatial operations:
models.py
from location_field.models.spatial import SpatialLocationField

class Restaurant(models.Model):
    location = SpatialLocationField(based_fields=["address"], zoom=7)
    # Stored as PostGIS Point
SpatialLocationField requires GeoDjango and a spatial database like PostGIS.

Working with Locations

Accessing Coordinates

venue = Venue.objects.get(id=1)

# Get coordinates as string
print(venue.location)  # "40.7128,-74.0060"

# Parse coordinates
latitude, longitude = venue.location.split(",")
latitude = float(latitude)
longitude = float(longitude)

print(f"Lat: {latitude}, Lon: {longitude}")

Setting Coordinates

from myapp.models import Venue

# Create venue with coordinates
venue = Venue.objects.create(
    name="Empire State Building",
    address="350 5th Ave, New York, NY 10118",
    location="40.748817,-73.985428"  # lat,lon format
)

Querying Locations

# Find venues with coordinates
venues = Venue.objects.exclude(location="")

# Filter by specific location
venue = Venue.objects.filter(location="40.7128,-74.0060")

Advanced Configuration

Multiple Location Fields

models.py
class Event(models.Model):
    name = models.CharField(max_length=200)
    
    # Primary venue
    venue_address = models.TextField()
    venue_location = PlainLocationField(
        based_fields=["venue_address"],
        zoom=12
    )
    
    # Parking location
    parking_address = models.TextField(blank=True)
    parking_location = PlainLocationField(
        based_fields=["parking_address"],
        zoom=15,
        blank=True
    )
admin.py
class EventAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        self.fields["venue_location"].widget = UnfoldAdminLocationWidget(
            based_fields=["venue_address"],
            zoom=12
        )
        
        self.fields["parking_location"].widget = UnfoldAdminLocationWidget(
            based_fields=["parking_address"],
            zoom=15
        )

Custom Map Configuration

Customize the map provider and settings:
settings.py
# Default is OpenStreetMap
LOCATION_FIELD = {
    "provider.google.api": "//maps.google.com/maps/api/js?sensor=false",
    "provider.google.api_key": "YOUR_GOOGLE_MAPS_API_KEY",
    "provider.google.api_libraries": "",
    "provider.google.map.type": "ROADMAP",
}

Geocoding

Add automatic geocoding:
models.py
from django.contrib.gis.geos import Point

class Place(models.Model):
    name = models.CharField(max_length=200)
    address = models.TextField()
    location = PlainLocationField(based_fields=["address"], zoom=7)
    
    def save(self, *args, **kwargs):
        # Auto-geocode if location is empty
        if not self.location and self.address:
            # Use geocoding service
            coordinates = geocode_address(self.address)
            if coordinates:
                self.location = f"{coordinates['lat']},{coordinates['lon']}"
        
        super().save(*args, **kwargs)

Integration with GeoDjango

For spatial queries, use SpatialLocationField:
models.py
from django.contrib.gis.db import models
from location_field.models.spatial import SpatialLocationField

class Location(models.Model):
    name = models.CharField(max_length=200)
    point = SpatialLocationField(based_fields=["address"], zoom=7)
    
    objects = models.Manager()

Spatial Queries

from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D

# Find locations within 10km of a point
reference_point = Point(-73.985428, 40.748817, srid=4326)

nearby = Location.objects.filter(
    point__distance_lte=(reference_point, D(km=10))
)

# Find closest location
closest = Location.objects.annotate(
    distance=models.Distance("point", reference_point)
).order_by("distance").first()

Display on Frontend

Show Map in Templates

templates/venue_detail.html
{% load static %}

<div class="venue-map">
    <h2>{{ venue.name }}</h2>
    <p>{{ venue.address }}</p>
    
    {% if venue.location %}
        <div id="map" style="width: 100%; height: 400px;"></div>
        
        <script>
            var coordinates = "{{ venue.location }}".split(",");
            var lat = parseFloat(coordinates[0]);
            var lon = parseFloat(coordinates[1]);
            
            // Initialize map with your preferred library
            var map = L.map('map').setView([lat, lon], 13);
            L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
            L.marker([lat, lon]).addTo(map)
                .bindPopup("{{ venue.name }}");
        </script>
    {% endif %}
</div>

Use Cases

Display store locations on a map:
models.py
class Store(models.Model):
    name = models.CharField(max_length=200)
    address = models.TextField()
    city = models.CharField(max_length=100)
    location = PlainLocationField(
        based_fields=["address", "city"],
        zoom=12
    )
    phone = models.CharField(max_length=20)
    hours = models.TextField()
Manage event locations:
models.py
class Event(models.Model):
    name = models.CharField(max_length=200)
    venue_name = models.CharField(max_length=200)
    venue_address = models.TextField()
    location = PlainLocationField(
        based_fields=["venue_address"],
        zoom=15
    )
    event_date = models.DateTimeField()
Define delivery areas:
models.py
class DeliveryZone(models.Model):
    name = models.CharField(max_length=100)
    center_location = PlainLocationField(
        based_fields=["name"],
        zoom=10
    )
    radius_km = models.DecimalField(max_digits=5, decimal_places=2)
Real estate locations:
models.py
class Property(models.Model):
    title = models.CharField(max_length=200)
    address = models.TextField()
    city = models.CharField(max_length=100)
    location = PlainLocationField(
        based_fields=["address", "city"],
        zoom=14
    )
    price = models.DecimalField(max_digits=10, decimal_places=2)

Map Providers

OpenStreetMap (Default)

Free and open source:
# No configuration needed, works out of the box

Google Maps

Requires API key:
settings.py
LOCATION_FIELD = {
    "map.provider": "google",
    "provider.google.api_key": "YOUR_API_KEY",
}

Mapbox

Alternative provider:
settings.py
LOCATION_FIELD = {
    "map.provider": "mapbox",
    "provider.mapbox.access_token": "YOUR_TOKEN",
}

Troubleshooting

Ensure JavaScript is enabled and check browser console for errors. Verify that the map provider API key is correct if using Google Maps or Mapbox.
Check that based_fields are correctly specified and contain valid address data. Ensure the geocoding service is accessible.
Verify that the location field is not marked as read-only and that the form is properly configured with the UnfoldAdminLocationWidget.

Resources

Django Location Field

Official GitHub repository and documentation

GeoDjango Docs

Django’s geographic framework documentation
For better user experience, pre-populate the address field to automatically position the map when creating new records.

Build docs developers (and LLMs) love