When I started my current position, I inherited a Django Rest API that sits on top of our Postgres database. It was still running on Django v.1.7.11. Now almost two years later, I decided it's finally time to upgrade.
I first upgraded to Django v1.11.29 (planning on getting it more current, but wanted to upgrade somewhat incrementally). I fixed any errors caused by the upgrade and was all set. I was able to access it and everything worked properly, except for reading data from one table. This table contains four date fields, and when accessing it's API endpoint, I get the following error:
Request Method: GET
Request URL: http://obis.twalk.tech:81/api/obis/occurrence/
Django Version: 1.11.29
Exception Type: ValueError
Exception Value:
year is out of range
Exception Location: /usr/local/lib/python2.7/site-packages/django/db/utils.py in inner, line 101
Python Executable: /usr/local/bin/python
Python Version: 2.7.18
From what I could tell initially with the debug output, this error was caused by having a null values in one of the date fields. I'm working in a personal development environment so I was able to change, at the database level, each instance of a null value in any of the date fields to be a properly formatted date. I still got the same error. I changed the field type in my model to be a text field instead of a date field; same error still occurs.
I've been stuck on this for about a week now, and after much research and many failed attempts to solve this, I'm at a loss. Does anybody have any suggestions or insight on what's going on here? I've posted the relevant code and traceback below.
models.py (the relevant fields are commented here for visibility):
class Occurrence(models.Model):
resourcetype = models.ForeignKey('ResourceTypeLookup', db_column='resourcetype', blank=True, null=True)
gid = models.IntegerField(primary_key=True)
acode = models.ForeignKey(Acctax, db_column='acode', blank=True, null=True)
# eventdate = models.DateField(blank=True, null=True)
recordedby = models.CharField(max_length=500, blank=True)
county = models.ForeignKey(County, db_column='county', blank=True, null=True)
locality = models.CharField(max_length=500, blank=True)
behavior = models.CharField(max_length=500, blank=True)
habitat = models.CharField(max_length=500, blank=True)
sex = models.CharField(max_length=500, blank=True)
lifestage = models.CharField(max_length=500, blank=True)
associatedtaxa = models.CharField(max_length=500, blank=True)
verbatimelevation = models.FloatField(blank=True, null=True)
depth = models.FloatField(blank=True, null=True)
depthaccuracy = models.IntegerField(blank=True, null=True)
individualcount = models.IntegerField(blank=True, null=True)
occurrenceremarks = models.CharField(max_length=500, blank=True)
taxonremarks = models.CharField(max_length=500, blank=True)
institutioncode = models.ForeignKey(Institution, db_column='institutioncode', blank=True, null=True)
basisofrecord = models.ForeignKey(BasisOfRecordLookup, db_column='basisofrecord', blank=True, null=True)
catalognumber = models.CharField(max_length=500, blank=True)
othercatalognumbers = models.CharField(max_length=500, blank=True)
typestatus = models.CharField(max_length=25, blank=True)
recordnumber = models.CharField(max_length=500, blank=True)
samplingprotocol = models.CharField(max_length=500, blank=True)
preparations = models.CharField(max_length=500, blank=True)
primary_data = models.CharField(max_length=500, blank=True)
associatedreferences = models.CharField(max_length=500, blank=True)
datasetname = models.ForeignKey('Source', db_column='datasetname', blank=True, null=True)
coordinateprecision = models.IntegerField(blank=True, null=True)
decimallatitude = models.FloatField(blank=True, null=True)
decimallongitude = models.FloatField(blank=True, null=True)
geodeticdatum = models.CharField(max_length=10, blank=True)
georeferencedby = models.CharField(max_length=500, blank=True)
# georeferenceddate = models.DateField(blank=True, null=True)
georeferenceremarks = models.CharField(max_length=500, blank=True)
georeferencesources = models.CharField(max_length=500, blank=True)
georeferenceverificationstatus = models.CharField(max_length=500, blank=True)
geom = models.TextField(blank=True) # This field type is a guess.
problem_with_record = models.CharField(max_length=500, blank=True)
previousidentifications = models.CharField(max_length=500, blank=True)
identificationverificationstatus = models.CharField(max_length=500, blank=True)
identificationconfidence = models.CharField(max_length=10, blank=True)
identificationremarks = models.CharField(max_length=500, blank=True)
# datelastmodified = models.DateField(blank=True, null=True)
associatedoccurrences = models.CharField(max_length=500, blank=True)
associatedsequences = models.CharField(max_length=500, blank=True)
entby = models.CharField(max_length=500, blank=True)
# entrydate = models.DateField(blank=True, null=True)
obs_gid = models.IntegerField(blank=True, null=True)
mtr = models.TextField(blank=True)
township = models.IntegerField(blank=True, null=True)
ns = models.TextField(blank=True)
range = models.IntegerField(blank=True, null=True)
ew = models.TextField(blank=True)
section = models.IntegerField(blank=True, null=True)
quarter = models.TextField(blank=True)
zone = models.IntegerField(blank=True, null=True)
utme = models.IntegerField(blank=True, null=True)
utmn = models.IntegerField(blank=True, null=True)
hiderecord = models.NullBooleanField()
hiderecordcomment = models.CharField(max_length=500, blank=True)
relationshipremarks = models.CharField(max_length=500, blank=True)
informationwitheld = models.NullBooleanField()
awaitingreview = models.IntegerField(blank=True, null=True)
occurrenceid = models.TextField(blank=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'occurrence'
filters.py:
class OccurrenceFilter(django_filters.FilterSet):
acode = django_filters.CharFilter(lookup_expr='exact')
catalognumber = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Occurrence
fields = '__all__'
serializers.py:
class OccurenceSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Occurrence
fields = ('url','resourcetype','gid','acode','eventdate','recordedby','county','locality','behavior','habitat','sex','lifestage','associatedtaxa','verbatimelevation','depth','depthaccuracy','individualcount','occurrenceremarks','taxonremarks','institutioncode','basisofrecord','catalognumber','othercatalognumbers','typestatus','recordnumber','samplingprotocol','preparations','primary_data','associatedreferences','datasetname','coordinateprecision','decimallatitude','decimallongitude','geodeticdatum','georeferencedby','georeferenceddate','georeferenceremarks','georeferencesources','georeferenceverificationstatus','geom','problem_with_record','previousidentifications','identificationverificationstatus','identificationconfidence','identificationremarks','datelastmodified','associatedoccurrences','associatedsequences','entby','entrydate','obs_gid','mtr','township','ns','range','ew','section','quarter','zone','utme','utmn','hiderecord','hiderecordcomment','relationshipremarks','informationwitheld','awaitingreview','occurrenceid')
views.py:
class OccurrenceViewSet(obisTableViewSet):
"""
This is the Occurrence ViewSet with hyperlinked tables.
"""
model = Occurrence
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
renderer_classes = (BrowsableAPIRenderer, JSONRenderer)
serializer_class = OccurenceSerializer
filter_class = OccurrenceFilter
search_fields = ('acode','catalognumber')
def get_queryset(self):
user = self.request.user
if user.is_authenticated() == False or user.is_staff:
return Occurrence.objects.all()
else:
institutioncodes = [g.name for g in user.groups.all()]
return Occurrence.objects.filter(institutioncode__in=institutioncodes)
Traceback:
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _legacy_get_response
249. response = self._get_response(request)
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
58. return view_func(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
116. return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
495. response = self.handle_exception(exc)
File "/usr/local/lib/python2.7/site-packages/rest_framework/views.py" in handle_exception
455. self.raise_uncaught_exception(exc)
File "/usr/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
492. response = handler(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list
48. return Response(serializer.data)
File "/usr/local/lib/python2.7/site-packages/rest_framework/serializers.py" in data
768. ret = super(ListSerializer, self).data
File "/usr/local/lib/python2.7/site-packages/rest_framework/serializers.py" in data
262. self._data = self.to_representation(self.instance)
File "/usr/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
686. self.child.to_representation(item) for item in iterable
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py" in __iter__
250. self._fetch_all()
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py" in _fetch_all
1121. self._result_cache = list(self._iterable_class(self))
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py" in __iter__
62. for row in compiler.results_iter(results):
File "/usr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in results_iter
844. for rows in results:
File "/usr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in cursor_iter
1289. sentinel):
File "/usr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in <lambda>
1288. for rows in iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)),
File "/usr/local/lib/python2.7/site-packages/django/db/utils.py" in inner
101. return func(*args, **kwargs)
Any help is much appreciated.