utils.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from collections import OrderedDict
  2. import datetime
  3. import json
  4. from django.core.serializers import serialize
  5. from dcim.constants import LENGTH_UNIT_CENTIMETER, LENGTH_UNIT_FOOT, LENGTH_UNIT_INCH, LENGTH_UNIT_METER
  6. def csv_format(data):
  7. """
  8. Encapsulate any data which contains a comma within double quotes.
  9. """
  10. csv = []
  11. for value in data:
  12. # Represent None or False with empty string
  13. if value is None or value is False:
  14. csv.append('')
  15. continue
  16. # Convert dates to ISO format
  17. if isinstance(value, (datetime.date, datetime.datetime)):
  18. value = value.isoformat()
  19. # Force conversion to string first so we can check for any commas
  20. if not isinstance(value, str):
  21. value = '{}'.format(value)
  22. # Double-quote the value if it contains a comma
  23. if ',' in value or '\n' in value:
  24. csv.append('"{}"'.format(value))
  25. else:
  26. csv.append('{}'.format(value))
  27. return ','.join(csv)
  28. def foreground_color(bg_color):
  29. """
  30. Return the ideal foreground color (black or white) for a given background color in hexadecimal RGB format.
  31. """
  32. bg_color = bg_color.strip('#')
  33. r, g, b = [int(bg_color[c:c + 2], 16) for c in (0, 2, 4)]
  34. if r * 0.299 + g * 0.587 + b * 0.114 > 186:
  35. return '000000'
  36. else:
  37. return 'ffffff'
  38. def dynamic_import(name):
  39. """
  40. Dynamically import a class from an absolute path string
  41. """
  42. components = name.split('.')
  43. mod = __import__(components[0])
  44. for comp in components[1:]:
  45. mod = getattr(mod, comp)
  46. return mod
  47. def model_names_to_filter_dict(names):
  48. """
  49. Accept a list of content types in the format ['<app>.<model>', '<app>.<model>', ...] and return a dictionary
  50. suitable for QuerySet filtering.
  51. """
  52. # TODO: This should match on the app_label as well as the model name to avoid potential duplicate names
  53. return {
  54. 'model__in': [model.split('.')[1] for model in names],
  55. }
  56. def serialize_object(obj, extra=None):
  57. """
  58. Return a generic JSON representation of an object using Django's built-in serializer. (This is used for things like
  59. change logging, not the REST API.) Optionally include a dictionary to supplement the object data.
  60. """
  61. json_str = serialize('json', [obj])
  62. data = json.loads(json_str)[0]['fields']
  63. # Include any custom fields
  64. if hasattr(obj, 'get_custom_fields'):
  65. data['custom_fields'] = {
  66. field.name: str(value) for field, value in obj.get_custom_fields().items()
  67. }
  68. # Include any tags
  69. if hasattr(obj, 'tags'):
  70. data['tags'] = [tag.name for tag in obj.tags.all()]
  71. # Append any extra data
  72. if extra is not None:
  73. data.update(extra)
  74. return data
  75. def dict_to_filter_params(d, prefix=''):
  76. """
  77. Translate a dictionary of attributes to a nested set of parameters suitable for QuerySet filtering. For example:
  78. {
  79. "name": "Foo",
  80. "rack": {
  81. "facility_id": "R101"
  82. }
  83. }
  84. Becomes:
  85. {
  86. "name": "Foo",
  87. "rack__facility_id": "R101"
  88. }
  89. And can be employed as filter parameters:
  90. Device.objects.filter(**dict_to_filter(attrs_dict))
  91. """
  92. params = {}
  93. for key, val in d.items():
  94. k = prefix + key
  95. if isinstance(val, dict):
  96. params.update(dict_to_filter_params(val, k + '__'))
  97. else:
  98. params[k] = val
  99. return params
  100. def deepmerge(original, new):
  101. """
  102. Deep merge two dictionaries (new into original) and return a new dict
  103. """
  104. merged = OrderedDict(original)
  105. for key, val in new.items():
  106. if key in original and isinstance(original[key], dict) and isinstance(val, dict):
  107. merged[key] = deepmerge(original[key], val)
  108. else:
  109. merged[key] = val
  110. return merged
  111. def to_meters(length, unit):
  112. """
  113. Convert the given length to meters.
  114. """
  115. length = int(length)
  116. if length < 0:
  117. raise ValueError("Length must be a positive integer")
  118. if unit == LENGTH_UNIT_METER:
  119. return length
  120. if unit == LENGTH_UNIT_CENTIMETER:
  121. return length / 100
  122. if unit == LENGTH_UNIT_FOOT:
  123. return length * 0.3048
  124. if unit == LENGTH_UNIT_INCH:
  125. return length * 0.3048 * 12
  126. raise ValueError("Unknown unit {}. Must be 'm', 'cm', 'ft', or 'in'.".format(unit))