8

I'm normalizing a database associated with a Django project and will be moving fields to different tables. As part of the implementation process, I'd like to throw a deprecation warning to my colleagues if they attempt to use the old attributes after adding the new tables before I actually remove the columns.

class Asset(Model):
    model = models.CharField(max_length=64, blank=True, null=True)
    part_number = models.CharField(max_length=32, blank=True, null=True) # this will be a redundant column to be deprecated
    company = models.ForeignKey('Company', models.CASCADE, blank=True, null=True) # this will be a redundant column to be deprecated
    # other database fields as attributes and class methods

My understanding is that I would need to add something along the lines of warnings.warn('<field name> is deprecated', DeprecationWarning) somewhere in the class, but where would I add it?

cck
  • 193
  • 1
  • 14

3 Answers3

8

Perhaps you could use Django's system check framework (introduced in Django 1.7).

Some interesting examples, using the system-check-framework for deprecation of custom fields, are provided in the migrations docs.

It seems you can also use this approach to mark standard fields on your model. Applied to the example from the original post, the following works for me (tested in Django 3.1.6).

class Asset(Model):
    ...
    company = models.ForeignKey('Company', models.CASCADE, blank=True, null=True)  
    company.system_check_deprecated_details = dict(
        msg='The Asset.company field has been deprecated.',
        hint='Use OtherModel.other_field instead.',
        id='fields.W900',  # pick a unique ID for your field.
    )
    ...

See the system check API reference for more detailed information, e.g. about the "unique ID".

The following warning will then show, whenever you call runserver, migrate, or other commands, as mentioned in the docs:

System check identified some issues:

WARNINGS:
myapp.Asset.company: (fields.W900) The Asset.company field has been deprecated.
    HINT: Use OtherModel.other_field instead.

Also nice to know (from the docs):

... For performance reasons, checks are not run as part of the WSGI stack that is used in deployment. ...

djvg
  • 11,722
  • 5
  • 72
  • 103
3

You can use django_deprication.DeprecatedField

pip install django-deprecation

then use like this

class Album(models.Model):
    name = DeprecatedField('title')

https://github.com/openbox/django-deprecation

Ryabchenko Alexander
  • 10,057
  • 7
  • 56
  • 88
  • Do you know perchance if this works with conversion to a ForeignKey? It looks like it should, but curious if you've tried. – DylanYoung Sep 16 '20 at 20:20
0

I do something similar to this - turn the field into a property and handle the warning there. Note that this will still break any queries you make that filter on the field - just helps with accessing the attribute from instances.

class NewAsset(Model):
    model = models.CharField(max_length=64, blank=True, null=True)

class Asset(Model):
    @property
    def model(self):
        log.warning('Stop using this')
        return NewAsset.model
Jens Astrup
  • 2,415
  • 2
  • 14
  • 20