-
Notifications
You must be signed in to change notification settings - Fork 19
/
deprecate_field.py
76 lines (61 loc) · 2.29 KB
/
deprecate_field.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import logging
import sys
import warnings
logger = logging.getLogger(__name__)
class FieldDeprecatedError(Exception):
pass
class DeprecatedField(object):
"""
Descriptor class for deprecated fields. Do not use directly, use the
deprecate_field function instead.
"""
def __init__(self, val, raise_on_access=False):
self.val = val
self.raise_on_access = raise_on_access
def _get_name(self, obj):
"""
Try to find this field's name in the model class
"""
for k, v in type(obj).__dict__.items():
if v is self:
return k
return "<unknown>"
def __get__(self, obj, type=None):
msg = "accessing deprecated field %s.%s" % (
obj.__class__.__name__,
self._get_name(obj),
)
if self.raise_on_access:
raise FieldDeprecatedError(msg)
warnings.warn(msg, DeprecationWarning, stacklevel=2)
logger.warning(msg)
if not callable(self.val):
return self.val
return self.val()
def __set__(self, obj, val):
msg = "writing to deprecated field %s.%s" % (
obj.__class__.__name__,
self._get_name(obj),
)
if self.raise_on_access:
raise FieldDeprecatedError(msg)
warnings.warn(msg, DeprecationWarning, stacklevel=2)
logger.warning(msg)
self.val = val
def deprecate_field(field_instance, return_instead=None, raise_on_access=False):
"""
Can be used in models to delete a Field in a Backwards compatible manner.
The process for deleting old model Fields is:
1. Mark a field as deprecated by wrapping the field with this function
2. Wait until (1) is deployed to every relevant server/branch
3. Delete the field from the model.
For (1) and (3) you need to run ./manage.py makemigrations:
:param field_instance: The field to deprecate
:param return_instead: A value or function that
the field will pretend to have
:param raise_on_access: If true, raise FieldDeprecated instead of logging a warning
"""
if not set(sys.argv) & {"makemigrations", "migrate", "showmigrations"}:
return DeprecatedField(return_instead, raise_on_access=raise_on_access)
field_instance.null = True
return field_instance