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.

Files for django-deprecation, version 0.1.1
Filename, size File type Python version Upload date Hashes
Filename, size django_deprecation-0.1.1-py2.py3-none-any.whl (3.9 kB) File type Wheel Python version py2.py3 Upload date Hashes View hashes
Filename, size django-deprecation-0.1.1.tar.gz (4.0 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page