querydict.py 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. from urllib.parse import urlencode
  2. from django.http import QueryDict
  3. from django.utils.datastructures import MultiValueDict
  4. from netbox.models.features import CloningMixin
  5. __all__ = (
  6. 'dict_to_querydict',
  7. 'normalize_querydict',
  8. 'prepare_cloned_fields',
  9. )
  10. def dict_to_querydict(d, mutable=True):
  11. """
  12. Create a QueryDict instance from a regular Python dictionary.
  13. """
  14. qd = QueryDict(mutable=True)
  15. for k, v in d.items():
  16. item = MultiValueDict({k: v}) if isinstance(v, (list, tuple, set)) else {k: v}
  17. qd.update(item)
  18. if not mutable:
  19. qd._mutable = False
  20. return qd
  21. def normalize_querydict(querydict):
  22. """
  23. Convert a QueryDict to a normal, mutable dictionary, preserving list values. For example,
  24. QueryDict('foo=1&bar=2&bar=3&baz=')
  25. becomes:
  26. {'foo': '1', 'bar': ['2', '3'], 'baz': ''}
  27. This function is necessary because QueryDict does not provide any built-in mechanism which preserves multiple
  28. values.
  29. """
  30. return {
  31. k: v if len(v) > 1 else v[0] for k, v in querydict.lists()
  32. }
  33. def prepare_cloned_fields(instance):
  34. """
  35. Generate a QueryDict comprising attributes from an object's clone() method.
  36. """
  37. # Generate the clone attributes from the instance
  38. if not issubclass(type(instance), CloningMixin):
  39. return QueryDict(mutable=True)
  40. attrs = instance.clone()
  41. # Prepare QueryDict parameters
  42. params = []
  43. for key, value in attrs.items():
  44. if type(value) in (list, tuple):
  45. params.extend([(key, v) for v in value])
  46. elif value is not False and value is not None:
  47. params.append((key, value))
  48. else:
  49. params.append((key, ''))
  50. # Return a QueryDict with the parameters
  51. return QueryDict(urlencode(params), mutable=True)