Add "shop" Table to Django Admin
In this video we will add our shop database table to our admin view and load some initial records.
At this point you should have most of your app set up along with a superuser account for Django authentication.
What you will do now is register your shop model in the Admin interface. To do so you will subclass a GeoDjango class called OSMGeoAdmin and specifying the list of columns to display for the view.
00:00
Welcome to video number nine in our series on creating a location-based web app with Django and GeoDjango. In this video, we will add our shop
database table to our admin view and load some initial records. At this point, you should have most of your app set up, along with a superuser account for Django authentication.
00:21
What you will do now is register your shop
model in the admin interface. To do so, you will subclass a GeoDjango class by the name of OSMGeoAdmin
, and specify the list of columns to display for the view.
00:37
Back in our editor, you’re going to modify a different file this time—admin.py
, located in the app part of your project. This file provides a way for you to customize the built-in admin pages.
00:49 Add the following code to this file.
00:56
If your site is still running, stop it by pressing Control + C at the terminal. Then relaunch your site with the manage.py runserver
command.
01:06
Go back into your site and then go to the admin view by typing /admin
after the URL in your address bar. You see a new link called Shops.
01:15 Django even capitalized the table name and made it plural for consistency. Let’s look inside. Not surprisingly, we have no shop data yet, but as you can see, the interface has provided a way for us to manually add records if we wanted.
01:29 Instead of doing that by hand, though, you’re going to load your database with some initial data courtesy of the overpass-turbo.eu website. Open this address in your browser.
01:43
Use the Wizard option on this site and type the following query: shop in Baltimore
. Build and run the query.
01:59 Once the query completes, choose the Export option at the top of the page, and then click the download link next to raw OSM data.
02:08
This downloads a file to your downloads area called export.json
. We want to place export.json
in the root of your project—at the same level as the manage.py
utility.
02:19
You can take a look inside the file if you’re curious about its structure. But what we’re going to do next is create a Django migration to move this data into our database. To do that, we’re going to execute a manage.py
command to initialize an empty migration for our nearbyshops
app.
02:37
First, we’ll stop our site by pressing Control + C, and then clean up our view a little. Notice the migrations/
folder falls within the app part of our project, within the nearby shops/
folder. If you expand this, you’ll see artifacts from our previous migration.
02:56
Open your terminal window now and proceed with the --empty
migration command.
03:07
If you refresh your migrations/
folder now, you’ll see an empty migration file has been created. You are going to make significant changes to this file.
03:16
You’ll need to add three import
statements for some functionality you’ll need. Next, you’ll create a variable to hold the name of your JSON file.
03:28
Then—and this is the lengthy part—you’ll need to complete the code for the following load_data()
function. The important parts to note here in the function is the name of your app, 'nearbyshops'
, and the model name that will be needed, 'Shop'
.
03:47
We have one more change to make in the Migration
class. Add the load_data
function to the operations
list.
03:58
Our migration is ready to go. We just have the final step now of running the manage.py migrate
command.
04:07 Everything looks good! Let’s relaunch our site and see if we see any shops.
04:20 We’ll go back into the admin view and click the Shops link.
04:26 Great job! You should now see your initial location data. Before we leave this admin view, let’s take a look at what the ADD SHOP button does for us.
04:39
Neat! The OSMGeoAdmin
class includes a map view—even though the location is a little off. You should be very pleased with how much you’ve accomplished so far.
04:49 We’re on the home stretch! To wrap up this project, we’re finally going to show our user which shops are nearby—in our next video.
snandw on June 22, 2019
please help I am getting the same error on a windows machine ,a quick reply would be appreciated i need to submit this as a project
Jackie Wilson RP Team on June 24, 2019
I am traveling with limited access. Do you mean to say your map data (location data in JSON) is causing the error?
drewewhite1 on Feb. 9, 2020
@abairy and @snandw, you may have solved your problem already. If not or for anyone who runs into this issue in the future, I was able to resolve the issue by specifying the encoding upon opening the file. So it looks something like this.
...
with open(str(jsonfile), encoding = "utf8") as datafile:
objects = json.load(datafile)
for obj....
Hope this helps!
Amr on Feb. 17, 2020
how to to use file.xlsx instead of file.json? and also how to add any type of file.
Mydhe on April 7, 2020
Just to add, the edit is done in your empty migration file for example mine is named 0002_auto_20200408_0157.py The edit is in this block;
with open(str**(jsonfile), encoding = "utf8") as **datafile:
objects = json.load(datafile)
for obj in objects['elements']:
try:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = tags.get('name','no-name')
longitude = obj.get('lon', 0)
latitude = obj.get('lat', 0)
location = fromstr(f'POINT({longitude} {latitude})', srid=4326)
Shop(name=name, location = location).save()
except KeyError:
pass
Thanks drewewhite1 for the pointer!
jacob6 on May 4, 2020
My Shops table is still empty…no error messages. This is my code:
# Generated by Django 3.0.5 on 2020-05-04 08:55
from django.db import migrations
import json
from django.contrib.gis.geos import fromstr
from pathlib import Path
DATA_FILENAME = 'export.json'
def load_data(apps, schema_editor):
Shop = apps.get_model('nearbyshops', 'Shop')
jsonfile = Path(__file__).parents[2] / DATA_FILENAME
with open(str(jsonfile)) as datafile:
objects = json.load(datafile)
for obj in objects['elements']:
try:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = tags.get('name', 'no-name')
longitude = obj.get('lon', 0)
latitude = obj.get('lat', 0)
location = fromstr(
f'POINT({longitude} {latitude})', srid=4326
)
Shop(name=name, location=location).save()
except KeyError:
pass
class Migration(migrations.Migration):
dependencies = [
('nearbyshops', '0001_initial'),
]
operations = [
migrations.RunPython(load_data)
]
jacob6 on May 5, 2020
I’ve been over my code a few times now. I’m now getting the following error message:
TypeError: Shop() got an unexpected keyword argument 'location'
My code is as follows:
# Generated by Django 3.0.5 on 2020-05-04 10:00
from django.db import migrations
import json
from django.contrib.gis.geos import fromstr
from pathlib import Path
DATA_FILENAME = 'export.json'
def load_data(apps, schema_editor):
Shop = apps.get_model('nearbyshops', 'Shop')
jsonfile = Path(__file__).parents[2] / DATA_FILENAME
with open(str(jsonfile)) as datafile:
objects = json.load(datafile)
for obj in objects['elements']:
try:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = tags.get('name', 'no-name')
longitude = obj.get('lon', 0)
latitude = obj.get('lat', 0)
location = fromstr(
f'POINT({longitude} {latitude})', srid=4326
)
Shop(name=name, location=location).save()
except KeyError:
pass
class Migration(migrations.Migration):
dependencies = [
('nearbyshops', '0001_initial'),
]
operations = [
migrations.RunPython(load_data)
]
As per the instructions in the video the export.json is on the same level as manage.py. I’ve been over this code a lot of times now, and I’ve tried googling, with no success…can anyone help out?
pmannion95 on July 23, 2020
Hi, I’m running into an odd error that I believe is related the map data but I’ve follow the instructions in the video for querying shops in Baltimore and downloading as raw OSM data.
django.contrib.gis.geos.error.GEOSException: Error encountered checking Geometry returned from GEOS C function "GEOSWKTReader_read_r".
My migration code is below, but otherwise I’m unsure of what may be the issue. I’ve retraced it, and redownloaded the export.json data to no avail.
My code is below: ``` # Generated by Django 3.0.8 on 2020-07-21 05:08
from django.db import migrations import json from django.contrib.gis.geos import fromstr from pathlib import Path
DATA_FILENAME = ‘export.json’
def load_data(apps, schema_editor): Shop = apps.get_model(‘nearbyshops’, ‘Shop’) jsonfile = Path(file).parents[2] / DATA_FILENAME
with open(str(jsonfile)) as datafile:
objects = json.load(datafile)
for obj in objects['elements']:
try:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = tags.get('name', 'no-name')
longitude = obj.get('lon', 0)
latitude = obj.get('lat', 0)
location = fromstr(f'POINT({longitude} {latitude}', srid=4326)
Shop(name=name, location=location).save()
except KeyError:
pass
class Migration(migrations.Migration):
dependencies = [
('nearbyshops', '0001_initial'),
]
operations = [
migrations.RunPython(load_data)
]
```
karakus on Sept. 19, 2020
FYI - After spending some ‘extended happy time’ googling and checking my installs and code, I discovered that attempting to view the location in /Admin using OSMGeoAdmin doesn’t display the map correctly if using Safari, but works using Chrome. Hope this helps others!
See FAQ here for the source of my new found wisdom.
Enjoying the style and pace of the Tutorial all the same!
mkpannah on March 1, 2021
from django.db import migrations
import json
from django.contrib.gis.geos import fromstr
from pathlib import Path
DATA_FILENAME = 'export.json'
def load_data(apps, schema_editor):
Shop = apps.get_model('nearbyshops', 'Shop')
jsonfile = Path(__file__).parents[2] / DATA_FILENAME
with open(str(jsonfile)) as datafile:
objects = json.load(datafile)
for obj in objects['elements']:
try:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = tags.get('name', 'no-name')
longitude = obj.get('lon', 0)
latitude = obj.get('lat', 0)
location = fromstr(
f'POINT({longitude} {latitude})', srid=4326
)
Shop(name=name, location=location).save()
except KeyError:
pass
class Migration(migrations.Migration):
dependencies = [
('nearbyshops', '0001_initial'),
]
operations = [
migrations.RunPython(load_data)
]
Please help me out here. My shops are not loading on my django site. Don’t know what happening.
Joe Madaus on Nov. 2, 2021
Not sure this was anyone’s issue, but be sure your syntax is correct. I found an error in my f-string, which was:
location = fromstr(
f'POINT({longitude}, {latitude}', srid=4326
I was shocked this didn’t pick up. Explanation why I was getting a GEOSException
versus a syntax error?
The correct syntax is:
location = fromstr(
f'POINT({longitude} {latitude})', srid=4326
)
One little closing parenthesis :)
Martin Breuss RP Team on Nov. 2, 2021
Oh the joys (and pains of missing parentheses! (we’ve (probably all been there…
) 😜
Thanks for the heads-up to check your syntax @ Joe Madaus! And to reduce the amount of times you run into annoying stuff like that, you can use a Python IDE or code editor that helps you by highlighting issues with your syntax right when you’re writing your code.
Joe Madaus on Nov. 3, 2021
Hi Martin
I do use PyCharm which is why I was perplexed. It was late though so it’s possible PyCharm was teling me but I didn’t see it. Really good tutorial. We should expand this to be more user interactive.
Martin Breuss RP Team on Nov. 3, 2021
Ah yes I also miss things like this every so often, despite all the IDE support! I’ll more quickly spot the mistake after it’s gone wrong though with the text editor highlighting :)
What do you mean about expanding it to be more user-interactive @Joe Madaus?
Joe Madaus on Nov. 4, 2021
Hello again Martin. First, thanks for listening to feedback.
What I mean is a web form with users entering points on a map, those points autofilling a field. Then give the user the ability to input information about them. Kind of like a blog or something. Like a “places I’ve been” sort of thing with user “memories” they can share or not. Then rank those against “other user places” should the user choose to do so. Something like that.
Martin Breuss RP Team on Nov. 4, 2021
That’s a great addition to this project @Joe Madaus! 🙌 🗺
For implementing this, you’ll need a way for your users to submit content to your Django back end. Here are a couple of links that might help you piece that functionality together:
You’ll have to pick out the relevant content, but if you go through this process and keep working on it, you’ll definitely learn a lot about Django and you’ll have a cool project to show at the end! :D Let me know if you work it out, I’ll come and record some places there!
Joe Madaus on Nov. 4, 2021
Martin
Sounds awesome and thanks for the tips!!! I will definitely let you know when i finish it.
kimstar619 on Aug. 17, 2023
Hello there, When I run makemigrations it says ‘No changes detected’, any ideas? export.json is in the same place as shown in video. I’m on a Mac M1 running Ventura 13.5
thanks, Kim
kimstar619 on Aug. 17, 2023
Nevermind, figured it out, just a stupid mistake....
Rafael Tenorio Gama on April 24, 2024
I try everything to solve the problem with django.contrib.gis.admin import OSMGeoAdmin but doesn’t work at all!! I have follow all the steps and instructions on gdal.org/download.html but nothing solves too.
We need a update from that lesson on Real Python.
My error is: when run python manage.py runserver
ImportError: cannot import name ‘OSMGeoAdmin’ from ‘django.contrib.gis.admin’.
gabriel on May 13, 2024
@Rafael Tenorio Gama I got stuck on the same part but got it to work using the following in my admin.py file. However, i haven’t figured out how to make the list_display option work yet.
from django.contrib import admin
from django.contrib.gis.admin import GISModelAdmin
from .models import Shop
admin.site.register(Shop, GISModelAdmin)
I found this at the very bottom of the following django doc. GeoDjango Tutorial Hope this helps.
jwil on Sept. 8, 2024
@gabriel and @Rafael Tenorio Gama I was able to get it working with the following in admin.py
from django.contrib.gis import admin
from django.contrib.gis.admin import GISModelAdmin
from .models import Shop
@admin.register(Shop)
class ShopAdmin(GISModelAdmin):
list_display = ('name', 'location')
Also, I found GISModelAdmin by discovering this: django.readthedocs.io/en/4.2.x/ref/contrib/gis/admin.html#osmgeoadmin
Thierry Gagné on Oct. 2, 2024
Just want to say thanks to gabriel and jwil above me: I had the same problem as them and using GISModelAdmin instead of OSMGeoAdmin solved the issue. It is a shame RealPython does not want to update the Contents tab with these solutions.
Become a Member to join the conversation.
abairy on June 4, 2019
Hello When I try to migrate the data exported from overpass its giving me this error
File “C:\Users\13154\Anaconda3\lib\encodings\cp1252.py”, line 23, in decode return codecs.charmap_decode(input,self.errors,decoding_table)[0] UnicodeDecodeError: ‘charmap’ codec can’t decode byte 0x9d in position 26427: character maps to <undefined>