Test case models.py:
from django.db import models
#------------------------------------------------------------------------------
class SimpleModel(models.Model):
month = models.PositiveIntegerField()
some_date = models.DateTimeField()
#------------------------------------------------------------------------------
class SecondModel(models.Model):
year = models.PositiveIntegerField()
some_date = models.DateTimeField()
Test case admin.py:
from django.contrib import admin
from datehierarchy.testbed.models import SimpleModel, SecondModel
#-------------------------------------------------------------------------------
class SimpleModelAdmin(admin.ModelAdmin):
list_display = ('month', 'some_date',)
date_hierarchy = 'some_date'
admin.site.register(SimpleModel, SimpleModelAdmin)
#-------------------------------------------------------------------------------
class SecondModelAdmin(admin.ModelAdmin):
list_display = ('year', 'some_date',)
date_hierarchy = 'some_date'
# Content Models
admin.site.register(SecondModel, SecondModelAdmin)
Produces tracebacks like this even if valid dates are present:
Traceback:
File "/home/lakin/Desktop/django/core/handlers/base.py" in get_response
92. response = callback(request, *callback_args, **callback_kwargs)
File "/home/lakin/Desktop/django/contrib/admin/options.py" in wrapper
226. return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/lakin/Desktop/django/views/decorators/cache.py" in _wrapped_view_func
44. response = view_func(request, *args, **kwargs)
File "/home/lakin/Desktop/django/contrib/admin/sites.py" in inner
186. return view(request, *args, **kwargs)
File "/home/lakin/Desktop/django/contrib/admin/options.py" in changelist_view
986. ], context, context_instance=context_instance)
File "/home/lakin/Desktop/django/shortcuts/__init__.py" in render_to_response
20. return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/home/lakin/Desktop/django/template/loader.py" in render_to_string
108. return t.render(context_instance)
File "/home/lakin/Desktop/django/template/__init__.py" in render
178. return self.nodelist.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
779. bits.append(self.render_node(node, context))
File "/home/lakin/Desktop/django/template/debug.py" in render_node
71. result = node.render(context)
File "/home/lakin/Desktop/django/template/loader_tags.py" in render
97. return compiled_parent.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
178. return self.nodelist.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
779. bits.append(self.render_node(node, context))
File "/home/lakin/Desktop/django/template/debug.py" in render_node
71. result = node.render(context)
File "/home/lakin/Desktop/django/template/loader_tags.py" in render
97. return compiled_parent.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
178. return self.nodelist.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
779. bits.append(self.render_node(node, context))
File "/home/lakin/Desktop/django/template/debug.py" in render_node
71. result = node.render(context)
File "/home/lakin/Desktop/django/template/loader_tags.py" in render
24. result = self.nodelist.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
779. bits.append(self.render_node(node, context))
File "/home/lakin/Desktop/django/template/debug.py" in render_node
71. result = node.render(context)
File "/home/lakin/Desktop/django/template/loader_tags.py" in render
24. result = self.nodelist.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
779. bits.append(self.render_node(node, context))
File "/home/lakin/Desktop/django/template/debug.py" in render_node
71. result = node.render(context)
File "/home/lakin/Desktop/django/template/__init__.py" in render
936. dict = func(*args)
File "/home/lakin/Desktop/django/contrib/admin/templatetags/admin_list.py" in date_hierarchy
313. } for year in years]
File "/home/lakin/Desktop/django/db/models/query.py" in _result_iter
106. self._fill_cache()
File "/home/lakin/Desktop/django/db/models/query.py" in _fill_cache
692. self._result_cache.append(self._iter.next())
File "/home/lakin/Desktop/django/db/models/sql/subqueries.py" in results_iter
397. date = typecast_timestamp(str(date))
File "/home/lakin/Desktop/django/db/backends/util.py" in typecast_timestamp
68. if not ' ' in s: return typecast_date(s)
File "/home/lakin/Desktop/django/db/backends/util.py" in typecast_date
53. return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null
Exception Type: ValueError at /admin/testbed/secondmodel/
Exception Value: invalid literal for int() with base 10: 'None'
This is due to the use of double quotes in queries like the following:
SELECT DISTINCT django_date_trunc('year', "testbed_secondmodel"."some_date") FROM "testbed_secondmodel" ORDER BY 1 ASC
Double quotes refer to column names, and int he above test case, the table testbed_secondmodel has a column named year
, and as such the value of year
is passed into the the python function _sqlite_date_trunc
- instead of the string "year"
. Instead, if one uses single quotes as per the string constant section in http://www.sqlite.org/lang_expr.html - it works just fine.
Possible patch:
Index: sqlite3/base.py
===================================================================
--- sqlite3/base.py (revision 12398)
+++ sqlite3/base.py (working copy)
@@ -65,12 +65,12 @@
def date_extract_sql(self, lookup_type, field_name):
# sqlite doesn't support extract, so we fake it with the user-defined
# function django_extract that's registered in connect().
- return 'django_extract("%s", %s)' % (lookup_type.lower(), field_name)
+ return 'django_extract(\'%s\', %s)' % (lookup_type.lower(), field_name)
def date_trunc_sql(self, lookup_type, field_name):
# sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined
# function django_date_trunc that's registered in connect().
- return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
+ return 'django_date_trunc(\'%s\', %s)' % (lookup_type.lower(), field_name)
def drop_foreignkey_sql(self):
return ""
I can confirm the issue. It's pretty obvious what's going wrong (and well summarised in the title of this ticket)