Skip to content

Commit d06681a

Browse files
committed
Closes #17761: Store empty CharField choices as null
1 parent 75270c1 commit d06681a

23 files changed

+622
-25
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from django.db import migrations, models
2+
3+
4+
def set_null_values(apps, schema_editor):
5+
"""
6+
Replace empty strings with null values.
7+
"""
8+
Circuit = apps.get_model('circuits', 'Circuit')
9+
CircuitGroupAssignment = apps.get_model('circuits', 'CircuitGroupAssignment')
10+
CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
11+
12+
Circuit.objects.filter(distance_unit='').update(distance_unit=None)
13+
CircuitGroupAssignment.objects.filter(priority='').update(priority=None)
14+
CircuitTermination.objects.filter(cable_end='').update(cable_end=None)
15+
16+
17+
class Migration(migrations.Migration):
18+
19+
dependencies = [
20+
('circuits', '0045_circuit_distance'),
21+
]
22+
23+
operations = [
24+
migrations.AlterField(
25+
model_name='circuit',
26+
name='distance_unit',
27+
field=models.CharField(blank=True, max_length=50, null=True),
28+
),
29+
migrations.AlterField(
30+
model_name='circuitgroupassignment',
31+
name='priority',
32+
field=models.CharField(blank=True, max_length=50, null=True),
33+
),
34+
migrations.AlterField(
35+
model_name='circuittermination',
36+
name='cable_end',
37+
field=models.CharField(blank=True, max_length=1, null=True),
38+
),
39+
migrations.RunPython(
40+
code=set_null_values,
41+
reverse_code=migrations.RunPython.noop
42+
),
43+
]

netbox/circuits/models/circuits.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ class CircuitGroupAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin,
187187
verbose_name=_('priority'),
188188
max_length=50,
189189
choices=CircuitPriorityChoices,
190-
blank=True
190+
blank=True,
191+
null=True
191192
)
192193
prerequisite_models = (
193194
'circuits.Circuit',
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
from django.db import migrations, models
2+
3+
4+
def set_null_values(apps, schema_editor):
5+
"""
6+
Replace empty strings with null values.
7+
"""
8+
Cable = apps.get_model('dcim', 'Cable')
9+
ConsolePort = apps.get_model('dcim', 'ConsolePort')
10+
ConsolePortTemplate = apps.get_model('dcim', 'ConsolePortTemplate')
11+
ConsoleServerPort = apps.get_model('dcim', 'ConsoleServerPort')
12+
ConsoleServerPortTemplate = apps.get_model('dcim', 'ConsoleServerPortTemplate')
13+
Device = apps.get_model('dcim', 'Device')
14+
DeviceType = apps.get_model('dcim', 'DeviceType')
15+
FrontPort = apps.get_model('dcim', 'FrontPort')
16+
Interface = apps.get_model('dcim', 'Interface')
17+
InterfaceTemplate = apps.get_model('dcim', 'InterfaceTemplate')
18+
ModuleType = apps.get_model('dcim', 'ModuleType')
19+
PowerFeed = apps.get_model('dcim', 'PowerFeed')
20+
PowerOutlet = apps.get_model('dcim', 'PowerOutlet')
21+
PowerOutletTemplate = apps.get_model('dcim', 'PowerOutletTemplate')
22+
PowerPort = apps.get_model('dcim', 'PowerPort')
23+
PowerPortTemplate = apps.get_model('dcim', 'PowerPortTemplate')
24+
Rack = apps.get_model('dcim', 'Rack')
25+
RackType = apps.get_model('dcim', 'RackType')
26+
RearPort = apps.get_model('dcim', 'RearPort')
27+
28+
Cable.objects.filter(length_unit='').update(length_unit=None)
29+
Cable.objects.filter(type='').update(type=None)
30+
ConsolePort.objects.filter(cable_end='').update(cable_end=None)
31+
ConsolePort.objects.filter(type='').update(type=None)
32+
ConsolePortTemplate.objects.filter(type='').update(type=None)
33+
ConsoleServerPort.objects.filter(cable_end='').update(cable_end=None)
34+
ConsoleServerPort.objects.filter(type='').update(type=None)
35+
ConsoleServerPortTemplate.objects.filter(type='').update(type=None)
36+
Device.objects.filter(airflow='').update(airflow=None)
37+
Device.objects.filter(face='').update(face=None)
38+
DeviceType.objects.filter(airflow='').update(airflow=None)
39+
DeviceType.objects.filter(subdevice_role='').update(subdevice_role=None)
40+
DeviceType.objects.filter(weight_unit='').update(weight_unit=None)
41+
FrontPort.objects.filter(cable_end='').update(cable_end=None)
42+
Interface.objects.filter(cable_end='').update(cable_end=None)
43+
Interface.objects.filter(mode='').update(mode=None)
44+
Interface.objects.filter(poe_mode='').update(poe_mode=None)
45+
Interface.objects.filter(poe_type='').update(poe_type=None)
46+
Interface.objects.filter(rf_channel='').update(rf_channel=None)
47+
Interface.objects.filter(rf_role='').update(rf_role=None)
48+
InterfaceTemplate.objects.filter(poe_mode='').update(poe_mode=None)
49+
InterfaceTemplate.objects.filter(poe_type='').update(poe_type=None)
50+
InterfaceTemplate.objects.filter(rf_role='').update(rf_role=None)
51+
ModuleType.objects.filter(airflow='').update(airflow=None)
52+
ModuleType.objects.filter(weight_unit='').update(weight_unit=None)
53+
PowerFeed.objects.filter(cable_end='').update(cable_end=None)
54+
PowerOutlet.objects.filter(cable_end='').update(cable_end=None)
55+
PowerOutlet.objects.filter(feed_leg='').update(feed_leg=None)
56+
PowerOutlet.objects.filter(type='').update(type=None)
57+
PowerOutletTemplate.objects.filter(feed_leg='').update(feed_leg=None)
58+
PowerOutletTemplate.objects.filter(type='').update(type=None)
59+
PowerPort.objects.filter(cable_end='').update(cable_end=None)
60+
PowerPort.objects.filter(type='').update(type=None)
61+
PowerPortTemplate.objects.filter(type='').update(type=None)
62+
Rack.objects.filter(airflow='').update(airflow=None)
63+
Rack.objects.filter(form_factor='').update(form_factor=None)
64+
Rack.objects.filter(outer_unit='').update(outer_unit=None)
65+
Rack.objects.filter(weight_unit='').update(weight_unit=None)
66+
RackType.objects.filter(outer_unit='').update(outer_unit=None)
67+
RackType.objects.filter(weight_unit='').update(weight_unit=None)
68+
RearPort.objects.filter(cable_end='').update(cable_end=None)
69+
70+
71+
class Migration(migrations.Migration):
72+
73+
dependencies = [
74+
('dcim', '0193_poweroutlet_color'),
75+
]
76+
77+
operations = [
78+
migrations.AlterField(
79+
model_name='cable',
80+
name='length_unit',
81+
field=models.CharField(blank=True, max_length=50, null=True),
82+
),
83+
migrations.AlterField(
84+
model_name='cable',
85+
name='type',
86+
field=models.CharField(blank=True, max_length=50, null=True),
87+
),
88+
migrations.AlterField(
89+
model_name='consoleport',
90+
name='cable_end',
91+
field=models.CharField(blank=True, max_length=1, null=True),
92+
),
93+
migrations.AlterField(
94+
model_name='consoleport',
95+
name='type',
96+
field=models.CharField(blank=True, max_length=50, null=True),
97+
),
98+
migrations.AlterField(
99+
model_name='consoleporttemplate',
100+
name='type',
101+
field=models.CharField(blank=True, max_length=50, null=True),
102+
),
103+
migrations.AlterField(
104+
model_name='consoleserverport',
105+
name='cable_end',
106+
field=models.CharField(blank=True, max_length=1, null=True),
107+
),
108+
migrations.AlterField(
109+
model_name='consoleserverport',
110+
name='type',
111+
field=models.CharField(blank=True, max_length=50, null=True),
112+
),
113+
migrations.AlterField(
114+
model_name='consoleserverporttemplate',
115+
name='type',
116+
field=models.CharField(blank=True, max_length=50, null=True),
117+
),
118+
migrations.AlterField(
119+
model_name='device',
120+
name='airflow',
121+
field=models.CharField(blank=True, max_length=50, null=True),
122+
),
123+
migrations.AlterField(
124+
model_name='device',
125+
name='face',
126+
field=models.CharField(blank=True, max_length=50, null=True),
127+
),
128+
migrations.AlterField(
129+
model_name='devicetype',
130+
name='airflow',
131+
field=models.CharField(blank=True, max_length=50, null=True),
132+
),
133+
migrations.AlterField(
134+
model_name='devicetype',
135+
name='subdevice_role',
136+
field=models.CharField(blank=True, max_length=50, null=True),
137+
),
138+
migrations.AlterField(
139+
model_name='devicetype',
140+
name='weight_unit',
141+
field=models.CharField(blank=True, max_length=50, null=True),
142+
),
143+
migrations.AlterField(
144+
model_name='frontport',
145+
name='cable_end',
146+
field=models.CharField(blank=True, max_length=1, null=True),
147+
),
148+
migrations.AlterField(
149+
model_name='interface',
150+
name='cable_end',
151+
field=models.CharField(blank=True, max_length=1, null=True),
152+
),
153+
migrations.AlterField(
154+
model_name='interface',
155+
name='mode',
156+
field=models.CharField(blank=True, max_length=50, null=True),
157+
),
158+
migrations.AlterField(
159+
model_name='interface',
160+
name='poe_mode',
161+
field=models.CharField(blank=True, max_length=50, null=True),
162+
),
163+
migrations.AlterField(
164+
model_name='interface',
165+
name='poe_type',
166+
field=models.CharField(blank=True, max_length=50, null=True),
167+
),
168+
migrations.AlterField(
169+
model_name='interface',
170+
name='rf_channel',
171+
field=models.CharField(blank=True, max_length=50, null=True),
172+
),
173+
migrations.AlterField(
174+
model_name='interface',
175+
name='rf_role',
176+
field=models.CharField(blank=True, max_length=30, null=True),
177+
),
178+
migrations.AlterField(
179+
model_name='interfacetemplate',
180+
name='poe_mode',
181+
field=models.CharField(blank=True, max_length=50, null=True),
182+
),
183+
migrations.AlterField(
184+
model_name='interfacetemplate',
185+
name='poe_type',
186+
field=models.CharField(blank=True, max_length=50, null=True),
187+
),
188+
migrations.AlterField(
189+
model_name='interfacetemplate',
190+
name='rf_role',
191+
field=models.CharField(blank=True, max_length=30, null=True),
192+
),
193+
migrations.AlterField(
194+
model_name='moduletype',
195+
name='airflow',
196+
field=models.CharField(blank=True, max_length=50, null=True),
197+
),
198+
migrations.AlterField(
199+
model_name='moduletype',
200+
name='weight_unit',
201+
field=models.CharField(blank=True, max_length=50, null=True),
202+
),
203+
migrations.AlterField(
204+
model_name='powerfeed',
205+
name='cable_end',
206+
field=models.CharField(blank=True, max_length=1, null=True),
207+
),
208+
migrations.AlterField(
209+
model_name='poweroutlet',
210+
name='cable_end',
211+
field=models.CharField(blank=True, max_length=1, null=True),
212+
),
213+
migrations.AlterField(
214+
model_name='poweroutlet',
215+
name='feed_leg',
216+
field=models.CharField(blank=True, max_length=50, null=True),
217+
),
218+
migrations.AlterField(
219+
model_name='poweroutlet',
220+
name='type',
221+
field=models.CharField(blank=True, max_length=50, null=True),
222+
),
223+
migrations.AlterField(
224+
model_name='poweroutlettemplate',
225+
name='feed_leg',
226+
field=models.CharField(blank=True, max_length=50, null=True),
227+
),
228+
migrations.AlterField(
229+
model_name='poweroutlettemplate',
230+
name='type',
231+
field=models.CharField(blank=True, max_length=50, null=True),
232+
),
233+
migrations.AlterField(
234+
model_name='powerport',
235+
name='cable_end',
236+
field=models.CharField(blank=True, max_length=1, null=True),
237+
),
238+
migrations.AlterField(
239+
model_name='powerport',
240+
name='type',
241+
field=models.CharField(blank=True, max_length=50, null=True),
242+
),
243+
migrations.AlterField(
244+
model_name='powerporttemplate',
245+
name='type',
246+
field=models.CharField(blank=True, max_length=50, null=True),
247+
),
248+
migrations.AlterField(
249+
model_name='rack',
250+
name='airflow',
251+
field=models.CharField(blank=True, max_length=50, null=True),
252+
),
253+
migrations.AlterField(
254+
model_name='rack',
255+
name='form_factor',
256+
field=models.CharField(blank=True, max_length=50, null=True),
257+
),
258+
migrations.AlterField(
259+
model_name='rack',
260+
name='outer_unit',
261+
field=models.CharField(blank=True, max_length=50, null=True),
262+
),
263+
migrations.AlterField(
264+
model_name='rack',
265+
name='weight_unit',
266+
field=models.CharField(blank=True, max_length=50, null=True),
267+
),
268+
migrations.AlterField(
269+
model_name='racktype',
270+
name='outer_unit',
271+
field=models.CharField(blank=True, max_length=50, null=True),
272+
),
273+
migrations.AlterField(
274+
model_name='racktype',
275+
name='weight_unit',
276+
field=models.CharField(blank=True, max_length=50, null=True),
277+
),
278+
migrations.AlterField(
279+
model_name='rearport',
280+
name='cable_end',
281+
field=models.CharField(blank=True, max_length=1, null=True),
282+
),
283+
migrations.RunPython(
284+
code=set_null_values,
285+
reverse_code=migrations.RunPython.noop
286+
),
287+
]

netbox/dcim/models/cables.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class Cable(PrimaryModel):
4242
verbose_name=_('type'),
4343
max_length=50,
4444
choices=CableTypeChoices,
45-
blank=True
45+
blank=True,
46+
null=True
4647
)
4748
status = models.CharField(
4849
verbose_name=_('status'),
@@ -78,6 +79,7 @@ class Cable(PrimaryModel):
7879
max_length=50,
7980
choices=CableLengthUnitChoices,
8081
blank=True,
82+
null=True
8183
)
8284
# Stores the normalized length (in meters) for database ordering
8385
_abs_length = models.DecimalField(
@@ -206,7 +208,7 @@ def save(self, *args, **kwargs):
206208

207209
# Clear length_unit if no length is defined
208210
if self.length is None:
209-
self.length_unit = ''
211+
self.length_unit = None
210212

211213
super().save(*args, **kwargs)
212214

@@ -365,7 +367,7 @@ def delete(self, *args, **kwargs):
365367
termination = self.termination._meta.model.objects.get(pk=self.termination_id)
366368
termination.snapshot()
367369
termination.cable = None
368-
termination.cable_end = ''
370+
termination.cable_end = None
369371
termination.save()
370372

371373
super().delete(*args, **kwargs)

0 commit comments

Comments
 (0)