0051_migrate_customfields.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. from django.db import migrations
  2. from extras.choices import CustomFieldTypeChoices
  3. def deserialize_value(field, value):
  4. """
  5. Convert serialized values to JSON equivalents.
  6. """
  7. if field.type in (CustomFieldTypeChoices.TYPE_INTEGER):
  8. return int(value)
  9. if field.type == CustomFieldTypeChoices.TYPE_BOOLEAN:
  10. return bool(int(value))
  11. if field.type == CustomFieldTypeChoices.TYPE_SELECT:
  12. return field._choices.get(pk=int(value)).value
  13. return value
  14. def migrate_customfield_defaults(apps, schema_editor):
  15. """
  16. Copy old serialized defaults to native JSON types.
  17. """
  18. CustomField = apps.get_model('extras', 'CustomField')
  19. for customfield in CustomField.objects.exclude(default=''):
  20. try:
  21. if customfield.type == CustomFieldTypeChoices.TYPE_INTEGER:
  22. value = int(customfield.default)
  23. elif customfield.type == CustomFieldTypeChoices.TYPE_BOOLEAN:
  24. value = customfield.default in ['true', 'yes', '1']
  25. else:
  26. value = customfield.default
  27. except ValueError:
  28. raise ValueError(
  29. f'Invalid default value "{customfield.default}" found for {customfield.type} '
  30. f'custom field {customfield.name}'
  31. )
  32. CustomField.objects.filter(pk=customfield.pk).update(default2=value)
  33. def migrate_customfieldchoices(apps, schema_editor):
  34. """
  35. Collect all CustomFieldChoices for each applicable CustomField, and save them locally as an array on
  36. the CustomField instance.
  37. """
  38. CustomField = apps.get_model('extras', 'CustomField')
  39. CustomFieldChoice = apps.get_model('extras', 'CustomFieldChoice')
  40. for cf in CustomField.objects.filter(type='select'):
  41. cf.choices = [
  42. cfc.value for cfc in CustomFieldChoice.objects.filter(field=cf).order_by('weight', 'value')
  43. ]
  44. cf.save()
  45. def migrate_customfieldvalues(apps, schema_editor):
  46. """
  47. Copy data from CustomFieldValues into the custom_field_data JSON field on each model instance.
  48. """
  49. CustomFieldValue = apps.get_model('extras', 'CustomFieldValue')
  50. for cfv in CustomFieldValue.objects.prefetch_related('field').exclude(serialized_value=''):
  51. model = apps.get_model(cfv.obj_type.app_label, cfv.obj_type.model)
  52. # Read and update custom field value for each instance
  53. # TODO: This can be done more efficiently once .update() is supported for JSON fields
  54. cf_data = model.objects.filter(pk=cfv.obj_id).values('custom_field_data').first()
  55. try:
  56. cf_data['custom_field_data'][cfv.field.name] = deserialize_value(cfv.field, cfv.serialized_value)
  57. except ValueError as e:
  58. print(f'{cfv.field.name} ({cfv.field.type}): {cfv.serialized_value} ({cfv.pk})')
  59. raise e
  60. model.objects.filter(pk=cfv.obj_id).update(**cf_data)
  61. def fix_filter_logic_values(apps, schema_editor):
  62. """
  63. Fix invalid values for CustomField.filter_logic (see #5376)
  64. """
  65. CustomField = apps.get_model('extras', 'CustomField')
  66. CustomField.objects.filter(filter_logic="integer").update(filter_logic="loose")
  67. class Migration(migrations.Migration):
  68. dependencies = [
  69. ('circuits', '0020_custom_field_data'),
  70. ('dcim', '0117_custom_field_data'),
  71. ('extras', '0050_customfield_changes'),
  72. ('ipam', '0038_custom_field_data'),
  73. ('secrets', '0010_custom_field_data'),
  74. ('tenancy', '0010_custom_field_data'),
  75. ('virtualization', '0018_custom_field_data'),
  76. ]
  77. operations = [
  78. migrations.RunPython(
  79. code=migrate_customfield_defaults
  80. ),
  81. migrations.RunPython(
  82. code=migrate_customfieldchoices
  83. ),
  84. migrations.RunPython(
  85. code=migrate_customfieldvalues
  86. ),
  87. migrations.RunPython(
  88. code=fix_filter_logic_values
  89. ),
  90. ]