#29738: Django can't serialize DateTimeTZRange(lower=None, upper=None, bounds='[)') -------------------------------------+------------------------------------- Reporter: grahammayer | Owner: nobody Type: Bug | Status: new Component: contrib.postgres | Version: 2.0 Severity: Normal | Resolution: Keywords: rangefield, | Triage Stage: Accepted postgresql, psycopg2, migrations | Has patch: 0 | Needs documentation: 1 Needs tests: 1 | Patch needs improvement: 0 Easy pickings: 1 | UI/UX: 0 -------------------------------------+------------------------------------- Changes (by Nick Pope):
* component: Migrations => contrib.postgres * needs_tests: 0 => 1 * easy: 0 => 1 * keywords: => rangefield, postgresql, psycopg2, migrations * needs_docs: 0 => 1 * stage: Unreviewed => Accepted Old description: > Tried to use DateTimeTZRange(lower=None, upper=None, bounds='[)') as a > default for a model field and get the following error when running > 'python manage.py makemigrations': > Traceback (most recent call last): > File "manage.py", line 12, in <module> > execute_from_command_line(sys.argv) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/core/management/__init__.py", line 371, in > execute_from_command_line > utility.execute() > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/core/management/__init__.py", line 365, in execute > self.fetch_command(subcommand).run_from_argv(self.argv) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/core/management/base.py", line 288, in run_from_argv > self.execute(*args, **cmd_options) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/core/management/base.py", line 335, in execute > output = self.handle(*args, **options) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/core/management/commands/makemigrations.py", line 172, in > handle > self.write_migration_files(changes) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/core/management/commands/makemigrations.py", line 210, in > write_migration_files > migration_string = writer.as_string() > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/writer.py", line 151, in as_string > operation_string, operation_imports = > OperationWriter(operation).serialize() > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/writer.py", line 110, in serialize > _write(arg_name, arg_value) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/writer.py", line 74, in _write > arg_string, arg_imports = MigrationWriter.serialize(_arg_value) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/writer.py", line 279, in serialize > return serializer_factory(value).serialize() > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/serializer.py", line 203, in serialize > return self.serialize_deconstructed(path, args, kwargs) > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/serializer.py", line 90, in > serialize_deconstructed > arg_string, arg_imports = serializer_factory(arg).serialize() > File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- > packages/django/db/migrations/serializer.py", line 370, in > serializer_factory > "topics/migrations/#migration-serializing" % (value, > get_docs_version()) > ValueError: Cannot serialize: DateTimeTZRange(None, None, '[)') New description: Tried to use {{{DateTimeTZRange(lower=None, upper=None, bounds='[)')}}} as a default for a model field and get the following error when running {{{python manage.py makemigrations}}}: {{{ Traceback (most recent call last): File "manage.py", line 12, in <module> execute_from_command_line(sys.argv) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/core/management/__init__.py", line 371, in execute_from_command_line utility.execute() File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/core/management/__init__.py", line 365, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/core/management/base.py", line 288, in run_from_argv self.execute(*args, **cmd_options) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/core/management/base.py", line 335, in execute output = self.handle(*args, **options) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/core/management/commands/makemigrations.py", line 172, in handle self.write_migration_files(changes) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/core/management/commands/makemigrations.py", line 210, in write_migration_files migration_string = writer.as_string() File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/writer.py", line 151, in as_string operation_string, operation_imports = OperationWriter(operation).serialize() File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/writer.py", line 110, in serialize _write(arg_name, arg_value) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/writer.py", line 74, in _write arg_string, arg_imports = MigrationWriter.serialize(_arg_value) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/writer.py", line 279, in serialize return serializer_factory(value).serialize() File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/serializer.py", line 203, in serialize return self.serialize_deconstructed(path, args, kwargs) File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/serializer.py", line 90, in serialize_deconstructed arg_string, arg_imports = serializer_factory(arg).serialize() File "/home/grahammayer/logimeter/logimeter/lib/python3.6/site- packages/django/db/migrations/serializer.py", line 370, in serializer_factory "topics/migrations/#migration-serializing" % (value, get_docs_version()) ValueError: Cannot serialize: DateTimeTZRange(None, None, '[)') }}} -- Comment: Presumably you are using {{{default=DateTimeTZRange(lower=None, upper=None, bounds='[)')}}}? Could you provide a simple example project? The problem is that {{{psycopg2.extras.DateTimeTZRange}}} cannot be serialized into a migrations, see [https://docs.djangoproject.com/en/2.1/topics/migrations/#serializing- values documentation]. So there are a few options: a. Can you get away with using {{{default=None, null=True}}}? b. Does {{{default=(None, None)}}} work instead? (I believe this will be limited to the [http://initd.org/psycopg/docs/extras.html#psycopg2.extras.Range default bounds]: `[)`) c. You need to make {{{DateTimeTZRange}}} deconstructible which will allow for other bounds to be defined. We should be able to get away with making these range objects deconstructible as we only expect them to take simple arguments that are already supported by the serializer. Here is an example: {{{#!python from psycopg2.extras import DateTimeTZRange from django.contrib.postgres.fields import DateTimeRangeField from django.utils.deconstruct import deconstructible DateTimeTZRange = deconstructible(DateTimeTZRange, path='psycopg2.extras.DateTimeTZRange') class RangeTestModel(models.Model): a = DateTimeRangeField( default=None, null=True, ) b = DateTimeRangeField( default=(None, None), null=False, ) c = DateTimeRangeField( default=DateTimeTZRange(None, None, '[]'), null=False, ) }}} I managed to produce the following migration: {{{#!python import django.contrib.postgres.fields.ranges from django.db import migrations, models import psycopg2.extras class Migration(migrations.Migration): dependencies = [ ] operations = [ migrations.CreateModel( name='RangeTestModel', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('a', django.contrib.postgres.fields.ranges.DateTimeRangeField(default=None, null=True)), ('b', django.contrib.postgres.fields.ranges.DateTimeRangeField(default=(None, None))), ('c', django.contrib.postgres.fields.ranges.DateTimeRangeField(default=psycopg2.extras.DateTimeTZRange(None, None, '[]'))), ], ), ] }}} (Disclaimer: I have only attempted to produce migrations and not actually called {{{RangeTestModel.objects.create()}}}...) So in summary, I think that we only need to add some documentation to explain how to handle defaults for range fields and tests to ensure that it continues to work. -- Ticket URL: <https://code.djangoproject.com/ticket/29738#comment:1> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/069.84ef1660e9354733da1d8889263a516a%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.