Search code examples
pythondjangographene-python

django-graphene alter column name deprecation


I would like to alter a column name in a table my database, deprecate the old field in django-graphene and add the new field.

How or can I do this without creating the same column twice in my Django model? I can avoid errors during system checks while doing this, but still run into errors with my tests.

Model

class MyModel(BaseModel):
    my_column = models.CharField(
        max_length=255, blank=True, null=True)
    mycolumn = models.CharField(
        max_length=255, blank=True, null=True
        db_column='my_column')

Schema

class MyNode(DjangoObjectType):
    mycolumn = String(deprecation_reason='Deprecated')

Settings

SILENCED_SYSTEM_CHECKS = ['models.E007']

This works, however, now I try to run tests where I create a sample MyModel factory instance.

class TestMyModel(TestModelBase):
    def setUp(self):
        self.my_model = MyModel(my_model_nm='Some model')

Which, of course, throws an exception.

django.db.utils.ProgrammingError: column "my_column" specified more than once

I seem to be going about this wrong. How do I change a field name in django-graphene, deprecate the old name and have a new field reference the same column in my table?

graphene==1.2

graphene-django==1.2.1

graphql-core==1.0.1


Solution

  • Here's what we ended up doing.

    from graphene import String
    from graphene_django.converter import convert_django_field
    
    
    class AliasCharField(models.Field):
        """
        Alias for a CharField so that two fields may point to the same column.
        source: https://djangosnippets.org/snippets/10440/
        """
        def contribute_to_class(self, cls, name, virtual_only=False):
            super(AliasCharField, self).contribute_to_class(cls, name,
                                                            virtual_only=True)
            setattr(cls, name, self)
    
        def __get__(self, instance, instance_type=None):
            return getattr(instance, self.db_column)
    
    
    @convert_django_field.register(AliasCharField)
    def convert_alias_char_field_to_string(field, registry=None):
        """
        Tell graphene-django how to deal with AliasCharField.
        source: https://github.com/graphql-python/graphene-django/issues/303
        """
        depr_reason = getattr(field, 'deprecation_reason', None)
        return String(description=field.help_text,
                      deprecation_reason=depr_reason,
                      required=not field.null)
    
    
    class MyModel(BaseModel):
        my_column = models.CharField(
            max_length=255, blank=True, null=True)
        mycolumn = models.CharField(
            max_length=255, blank=True, null=True
            db_column='my_column')
        my_column.deprecation_reason = 'Deprecated'
    

    This works without suppressing the system check in settings.