Skip to main content

Deprecate django fields and make migrations without breaking existing code.

Project description

django-deprecation

build status coverage PyPI version python version django version

Deprecate django fields and make migrations without breaking existing code.

Install

pip install django-deprecation

Usage

TL;DR

# Before:
class Album(models.Model):
    name = models.CharField(max_length=50)


# After:
class Album(models.Model):
    name = DeprecatedField('title')
    title = models.CharField(max_length=50)


assert album.name == album.title
assert list(Album.objects.filter(name='foo')) == list(Album.objects.filter(title='foo'))

Long explanation

Let's suppose we have the following models:

from django.db import models


class Musician(models.Model):
    name = models.CharField(max_length=50)


class Album(models.Model):
    musician = models.ForeignKey(Musician, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)

Now, for some reason, let's suppose we want to rename the field Album#musician to Album#artist.

So we make the migration using the RenameField operation. The problem is that any existing code that used the old field would break.

We could create a property as an alias:

class Album(models.Model):
    artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)

    @property
    def musician(self):
        return self.artist

    @musician.setter
    def musician(self, value):
        self.artist = value

But any code using QuerySet#filter would break if it uses the musician field.

This is where django-deprecation comes handy. We set the musician field as a DeprecatedField and point it to the artist field:

from django_deprecation import DeprecatedField


class Album(models.Model):
    artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
    musician = DeprecatedField('artist')
    name = models.CharField(max_length=100)

Now, the following code snippet will work:

from .models import Album, Musician

album = Album.objects.first()
assert album.musician == album.artist

new_musician = Musician.objects.create(
    first_name='John',
    last_name='Doe',
    instrument='Guitar',
)
album.musician = new_musician
assert album.artist == new_musician

new_musician_album = Album.objects.filter(
    musician=new_musician,
).first()
new_artist_album = Album.objects.filter(
    artist=new_musician,
).first()
assert new_musician_album == new_artist_album

If you want to control how to report the error, replace the DeprecatedField.warn function with a custom one:

from django_deprecation import DeprecatedField


def warn_function(message):
    # do stuff
    import warnings
    warnings.warn(message, DeprecationWarning)


DeprecatedField.warn = warn_function

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-deprecation-0.1.1.tar.gz (4.0 kB view hashes)

Uploaded Source

Built Distribution

django_deprecation-0.1.1-py2.py3-none-any.whl (3.9 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page