Deprecate django fields and make migrations without breaking existing code.
pip install django-deprecation
# 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'))
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