I am bringing a data set from a .CSV file of addresses into a model in Django through the ImportExport plugin, and at the point of saving this the model runs a geocoding process with GeoPy.
90% of the time it works but there are a few entries that are coming up with the following error:
... in save _, latlon = geocoder.geocode(address) TypeError: cannot unpack non-iterable NoneType object
I am guessing that the geocoding is not finding an address but I'm not sure why it doesn't just leave the field empty. I've looked up relevant sections in Django Docs, GeoPy docs and google maps geocoding docs but don't seem to find any hint as to how to fix it.
below is the a more full trace back error output:
Traceback (most recent call last):
File "C:\Users\henry\webvenv\aavenv\lib\site-packages\import_export\resources.py", line 522, in import_row
self.save_instance(instance, using_transactions, dry_run)
File "C:\Users\henry\webvenv\aavenv\lib\site-packages\import_export\resources.py", line 315, in save_instance
instance.save()
File "C:\Users\henry\webvenv\project\architects\models.py", line 51, in save
_, latlon = geocoder.geocode(address)
TypeError: cannot unpack non-iterable NoneType object
Below is the app/model.py which is being populated by the .CSV file and running the geocoding process:
from django.conf import settings
from urllib.request import URLError
from django.contrib.gis.db import models
from django.contrib.gis import geos
import geopy.geocoders
from geopy.geocoders import GoogleV3
class Architect(models.Model):
id = models.CharField(max_length=100, primary_key=True)
sname = models.CharField(max_length=100)
fname = models.CharField(max_length=100)
a1 = models.CharField(max_length=100)
a2 = models.CharField(max_length=100)
a3 = models.CharField(max_length=100)
a4 = models.CharField(max_length=100)
a5 = models.CharField(max_length=100)
a6 = models.CharField(max_length=100)
pcode = models.CharField(max_length=100)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
location = models.PointField(u"longitude/latitude", blank=True, null=True)
objects = models.Manager()
#Original def:
# def __str__(self):
# return self.id
def __unicode__(self):
return self.id
def save(self, **kwargs):
if not self.location:
address = u'%s %s %s %s %s %s' % (self.a2, self.a3, self.a4, self.a5, self.a6, self.pcode)
address = address.encode('utf-8')
geocoder = GoogleV3(api_key='my API key')
try:
_, latlon = geocoder.geocode(address)
except (URLError, ValueError):
pass
else:
point = "POINT(%s %s)" % (latlon[1], latlon[0])
self.location = geos.fromstr(point)
super(Architect, self).save()
I seem to have fixed my issue now
My solution involved adding 'TypeError' to the exception.
I also added a timeout of 10 seconds to help with geocodes that were having session time out errors, it is my understanding the default timeout is 1 second with GeoPy.
If there is a cleaner or more efficient way for this code to be written I would appreciate the guidance.
...
def save(self, **kwargs):
if not self.location:
address = u'%s %s %s %s %s %s' % (self.a2, self.a3, self.a4, self.a5, self.a6, self.pcode)
address = address.encode('utf-8')
geocoder = GoogleV3(api_key='My API Key')
try:
_, latlon = geocoder.geocode(address, timeout=10)
except (URLError, ValueError, TypeError):
pass
else:
point = "POINT(%s %s)" % (latlon[1], latlon[0])
self.location = geos.fromstr(point)
super(Architect, self).save()