general.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import json
  2. import warnings
  3. from django.contrib.postgres.fields import ArrayField
  4. from django.db.models import Aggregate, BooleanField, JSONField, TextField, Value
  5. from django.utils.deprecation import RemovedInDjango51Warning
  6. from .mixins import OrderableAggMixin
  7. __all__ = [
  8. "ArrayAgg",
  9. "BitAnd",
  10. "BitOr",
  11. "BitXor",
  12. "BoolAnd",
  13. "BoolOr",
  14. "JSONBAgg",
  15. "StringAgg",
  16. ]
  17. class ArrayAgg(OrderableAggMixin, Aggregate):
  18. function = "ARRAY_AGG"
  19. template = "%(function)s(%(distinct)s%(expressions)s %(ordering)s)"
  20. allow_distinct = True
  21. @property
  22. def output_field(self):
  23. return ArrayField(self.source_expressions[0].output_field)
  24. class BitAnd(Aggregate):
  25. function = "BIT_AND"
  26. class BitOr(Aggregate):
  27. function = "BIT_OR"
  28. class BitXor(Aggregate):
  29. function = "BIT_XOR"
  30. class BoolAnd(Aggregate):
  31. function = "BOOL_AND"
  32. output_field = BooleanField()
  33. class BoolOr(Aggregate):
  34. function = "BOOL_OR"
  35. output_field = BooleanField()
  36. class JSONBAgg(OrderableAggMixin, Aggregate):
  37. function = "JSONB_AGG"
  38. template = "%(function)s(%(distinct)s%(expressions)s %(ordering)s)"
  39. allow_distinct = True
  40. output_field = JSONField()
  41. # RemovedInDjango51Warning: When the deprecation ends, remove __init__().
  42. def __init__(self, *expressions, default=None, **extra):
  43. super().__init__(*expressions, default=default, **extra)
  44. if (
  45. isinstance(default, Value)
  46. and isinstance(default.value, str)
  47. and not isinstance(default.output_field, JSONField)
  48. ):
  49. value = default.value
  50. try:
  51. decoded = json.loads(value)
  52. except json.JSONDecodeError:
  53. warnings.warn(
  54. "Passing a Value() with an output_field that isn't a JSONField as "
  55. "JSONBAgg(default) is deprecated. Pass default="
  56. f"Value({value!r}, output_field=JSONField()) instead.",
  57. stacklevel=2,
  58. category=RemovedInDjango51Warning,
  59. )
  60. self.default.output_field = self.output_field
  61. else:
  62. self.default = Value(decoded, self.output_field)
  63. warnings.warn(
  64. "Passing an encoded JSON string as JSONBAgg(default) is "
  65. f"deprecated. Pass default={decoded!r} instead.",
  66. stacklevel=2,
  67. category=RemovedInDjango51Warning,
  68. )
  69. class StringAgg(OrderableAggMixin, Aggregate):
  70. function = "STRING_AGG"
  71. template = "%(function)s(%(distinct)s%(expressions)s %(ordering)s)"
  72. allow_distinct = True
  73. output_field = TextField()
  74. def __init__(self, expression, delimiter, **extra):
  75. delimiter_expr = Value(str(delimiter))
  76. super().__init__(expression, delimiter_expr, **extra)