#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 [email protected].
To post to this group, send email to [email protected].
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.