#24434: Django Custom Field inherits ForeignKey deconstruct() fails
-------------------------------------+-------------------------------------
     Reporter:  greenbender          |                    Owner:  Akshat
                                     |  verma
         Type:  Bug                  |                   Status:  assigned
    Component:  Documentation        |                  Version:  1.7
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
  deconstruct,migration              |
    Has patch:  1                    |      Needs documentation:  1
  Needs tests:  1                    |  Patch needs improvement:  1
Easy pickings:  1                    |                    UI/UX:  1
-------------------------------------+-------------------------------------
Changes (by Akshat verma):

 * cc: Akshat verma (added)
 * needs_better_patch:  0 => 1
 * needs_tests:  0 => 1
 * easy:  0 => 1
 * has_patch:  0 => 1
 * ui_ux:  0 => 1


Old description:

> When creating a custom field that inherits from ForeignKey and sets the
> to field there are issues with deconstruction.
>
> Simplified example (models.py)
>
> {{{
> from django.db import models
> from django.contrib.auth.models import User
>

> class UserField(models.ForeignKey):
>
>     def __init__(self, *args, **kwargs):
>         kwargs['to'] = User
>         super(UserField, self).__init__(*args, **kwargs)
>
>     def deconstruct(self):
>         name, path, args, kwargs = super(UserField, self).deconstruct()
>         del kwargs['to']
>         return name, path, args, kwargs
>

> class FooBar(models.Model):
>     user = UserField()
> }}}
>
> When {{{python manage.py makemigrations}}} is run the following exception
> is raised.
>
> {{{
> Traceback (most recent call last):
>   File "manage.py", line 10, in <module>
>     execute_from_command_line(sys.argv)
>   File "/usr/local/lib/python2.7/dist-
> packages/django/core/management/__init__.py", line 385, in
> execute_from_command_line
>     utility.execute()
>   File "/usr/local/lib/python2.7/dist-
> packages/django/core/management/__init__.py", line 377, in execute
>     self.fetch_command(subcommand).run_from_argv(self.argv)
>   File "/usr/local/lib/python2.7/dist-
> packages/django/core/management/base.py", line 288, in run_from_argv
>     self.execute(*args, **options.__dict__)
>   File "/usr/local/lib/python2.7/dist-
> packages/django/core/management/base.py", line 338, in execute
>     output = self.handle(*args, **options)
>   File "/usr/local/lib/python2.7/dist-
> packages/django/core/management/commands/makemigrations.py", line 111, in
> handle
>     convert_apps=app_labels or None,
>   File "/usr/local/lib/python2.7/dist-
> packages/django/db/migrations/autodetector.py", line 40, in changes
>     changes = self._detect_changes(convert_apps, graph)
>   File "/usr/local/lib/python2.7/dist-
> packages/django/db/migrations/autodetector.py", line 139, in
> _detect_changes
>     self.generate_renamed_models()
>   File "/usr/local/lib/python2.7/dist-
> packages/django/db/migrations/autodetector.py", line 413, in
> generate_renamed_models
>     model_fields_def =
> self.only_relation_agnostic_fields(model_state.fields)
>   File "/usr/local/lib/python2.7/dist-
> packages/django/db/migrations/autodetector.py", line 79, in
> only_relation_agnostic_fields
>     del deconstruction[2]['to']
> KeyError: u'to'
> }}}
>
> It can be resolved by not removing the 'to' kwarg during deconstruction,
> however, this obviously leaves the unrequired 'to' kwarg in the
> constructor, as follows:
>
> {{{
> from django.db import models, migrations
> from django.conf import settings
> import bar.models
>

> class Migration(migrations.Migration):
>
>     dependencies = [
>         migrations.swappable_dependency(settings.AUTH_USER_MODEL),
>     ]
>
>     operations = [
>         migrations.CreateModel(
>             name='FooBar',
>             fields=[
>                 ('id', models.AutoField(verbose_name='ID',
> serialize=False, auto_created=True, primary_key=True)),
>                 ('user',
> bar.models.UserField(to=settings.AUTH_USER_MODEL)),
>             ],
>             options={
>             },
>             bases=(models.Model,),
>         ),
>     ]
> }}}
>
> I've tried a few variations on this (such as supplying User as the first
> arg to the super call), however, the result is much the same or creates
> additional problems.
>
> The solution proposed at ticket:22263 may solve this problem.

New description:

 When creating a custom field that inherits from ForeignKey and sets the to
 field there are issues with deconstruction.

 Simplified example (models.py)

 {{{
 from django.db import models
 from django.contrib.auth.models import User


 class UserField(models.ForeignKey):

     def __init__(self, *args, **kwargs):
         kwargs['to'] = User
         super(UserField, self).__init__(*args, **kwargs)

     def deconstruct(self):
         name, path, args, kwargs = super(UserField, self).deconstruct()
         del kwargs['to']
         return name, path, args, kwargs


 class FooBar(models.Model):
     user = UserField()
 }}}

 When {{{python manage.py makemigrations}}} is run the following exception
 is raised.

 {{{
 Traceback (most recent call last):
   File "manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/__init__.py", line 385, in
 execute_from_command_line
     utility.execute()
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/__init__.py", line 377, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/base.py", line 288, in run_from_argv
     self.execute(*args, **options.__dict__)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/base.py", line 338, in execute
     output = self.handle(*args, **options)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/commands/makemigrations.py", line 111, in
 handle
     convert_apps=app_labels or None,
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 40, in changes
     changes = self._detect_changes(convert_apps, graph)
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 139, in
 _detect_changes
     self.generate_renamed_models()
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 413, in
 generate_renamed_models
     model_fields_def =
 self.only_relation_agnostic_fields(model_state.fields)
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 79, in
 only_relation_agnostic_fields
     del deconstruction[2]['to']
 KeyError: u'to'
 }}}

 It can be resolved by not removing the 'to' kwarg during deconstruction,
 however, this obviously leaves the unrequired 'to' kwarg in the
 constructor, as follows:

 {{{
 from django.db import models, migrations
 from django.conf import settings
 import bar.models


 class Migration(migrations.Migration):

     dependencies = [
         migrations.swappable_dependency(settings.AUTH_USER_MODEL),
     ]

     operations = [
         migrations.CreateModel(
             name='FooBar',
             fields=[
                 ('id', models.AutoField(verbose_name='ID',
 serialize=False, auto_created=True, primary_key=True)),
                 ('user',
 bar.models.UserField(to=settings.AUTH_USER_MODEL)),
             ],
             options={
             },
             bases=(models.Model,),
         ),
     ]
 }}}

 I've tried a few variations on this (such as supplying User as the first
 arg to the super call), however, the result is much the same or creates
 additional problems.

 The solution proposed at ticket:22263 may solve this problem.



 #When creating a custom field that inherits from ForeignKey and sets the
 to field there are issues with deconstruction.

 Simplified example (models.py)
 from django.db import models
 from django.contrib.auth.models import User


 class UserField(models.ForeignKey):

     def __init__(self, *args, **kwargs):
         kwargs['to'] = User
         super(UserField, self).__init__(*args, **kwargs)

     def deconstruct(self):
         name, path, args, kwargs = super(UserField, self).deconstruct()
         del kwargs['to']
         return name, path, args, kwargs


 class FooBar(models.Model):
     user = UserField()

 #When python manage.py makemigrations the following exception is raised.

 Traceback (most recent call last):
   File "manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/__init__.py", line 385, in
 execute_from_command_line
     utility.execute()
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/__init__.py", line 377, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/base.py", line 288, in run_from_argv
     self.execute(*args, **options.__dict__)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/base.py", line 338, in execute
     output = self.handle(*args, **options)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/commands/makemigrations.py", line 111, in
 handle
     convert_apps=app_labels or None,
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 40, in changes
     changes = self._detect_changes(convert_apps, graph)
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 139, in
 _detect_changes
     self.generate_renamed_models()
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 413, in
 generate_renamed_models
     model_fields_def =
 self.only_relation_agnostic_fields(model_state.fields)
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 79, in
 only_relation_agnostic_fields
     del deconstruction[2]['to']
 KeyError: u'to'

 #It can be resolved by not removing the 'to' kwarg during deconstruction,
 however, this obviously leaves the unrequired 'to' kwarg #in the
 constructor, as follows:

 from django.db import models, migrations
 from django.conf import settings
 import bar.models


 class Migration(migrations.Migration):

     dependencies = [
         migrations.swappable_dependency(settings.AUTH_USER_MODEL),
     ]

     operations = [
         migrations.CreateModel(
             name='FooBar',
             fields=[
                 ('id', models.AutoField(verbose_name='ID',
 serialize=False, auto_created=True, primary_key=True)),
                 ('user',
 bar.models.UserField(to=settings.AUTH_USER_MODEL)),
             ],
             options={
             },
             bases=(models.Model,),
         ),
     ]

--

Comment:

 #When creating a custom field that inherits from ForeignKey and sets the
 to field there are issues with deconstruction.

 Simplified example (models.py)
 from django.db import models
 from django.contrib.auth.models import User


 class UserField(models.ForeignKey):

     def __init__(self, *args, **kwargs):
         kwargs['to'] = User
         super(UserField, self).__init__(*args, **kwargs)

     def deconstruct(self):
         name, path, args, kwargs = super(UserField, self).deconstruct()
         del kwargs['to']
         return name, path, args, kwargs


 class FooBar(models.Model):
     user = UserField()

 #When python manage.py makemigrations the following exception is raised.

 Traceback (most recent call last):
   File "manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/__init__.py", line 385, in
 execute_from_command_line
     utility.execute()
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/__init__.py", line 377, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/base.py", line 288, in run_from_argv
     self.execute(*args, **options.__dict__)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/base.py", line 338, in execute
     output = self.handle(*args, **options)
   File "/usr/local/lib/python2.7/dist-
 packages/django/core/management/commands/makemigrations.py", line 111, in
 handle
     convert_apps=app_labels or None,
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 40, in changes
     changes = self._detect_changes(convert_apps, graph)
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 139, in
 _detect_changes
     self.generate_renamed_models()
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 413, in
 generate_renamed_models
     model_fields_def =
 self.only_relation_agnostic_fields(model_state.fields)
   File "/usr/local/lib/python2.7/dist-
 packages/django/db/migrations/autodetector.py", line 79, in
 only_relation_agnostic_fields
     del deconstruction[2]['to']
 KeyError: u'to'

 #It can be resolved by not removing the 'to' kwarg during deconstruction,
 however, this obviously leaves the unrequired 'to' kwarg #in the
 constructor, as follows:

 from django.db import models, migrations
 from django.conf import settings
 import bar.models


 class Migration(migrations.Migration):

     dependencies = [
         migrations.swappable_dependency(settings.AUTH_USER_MODEL),
     ]

     operations = [
         migrations.CreateModel(
             name='FooBar',
             fields=[
                 ('id', models.AutoField(verbose_name='ID',
 serialize=False, auto_created=True, primary_key=True)),
                 ('user',
 bar.models.UserField(to=settings.AUTH_USER_MODEL)),
             ],
             options={
             },
             bases=(models.Model,),
         ),
     ]

-- 
Ticket URL: <https://code.djangoproject.com/ticket/24434#comment:7>
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 view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/010701874685a23d-3a460846-b1f1-427d-bd67-8c36d52be8da-000000%40eu-central-1.amazonses.com.

Reply via email to