pgpartition.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import sys
  2. from typing import Optional
  3. from django.conf import settings
  4. from django.core.management.base import BaseCommand
  5. from django.utils.module_loading import import_string
  6. from psqlextra.partitioning import PostgresPartitioningError
  7. class Command(BaseCommand):
  8. """Create new partitions and delete old ones according to the configured
  9. partitioning strategies."""
  10. help = "Create new partitions and delete old ones using the configured partitioning manager. The PSQLEXTRA_PARTITIONING_MANAGER setting must be configured."
  11. def add_arguments(self, parser):
  12. parser.add_argument(
  13. "--dry",
  14. "-d",
  15. action="store_true",
  16. help="When specified, no partition will be created/deleted. Just a simulation.",
  17. required=False,
  18. default=False,
  19. )
  20. parser.add_argument(
  21. "--yes",
  22. "-y",
  23. action="store_true",
  24. help="Answer yes to all questions. WARNING: You will not be asked before deleting a partition.",
  25. required=False,
  26. default=False,
  27. )
  28. parser.add_argument(
  29. "--using",
  30. "-u",
  31. help="Optional name of the database connection to use.",
  32. default="default",
  33. )
  34. parser.add_argument(
  35. "--skip-create",
  36. action="store_true",
  37. help="Do not create partitions.",
  38. required=False,
  39. default=False,
  40. )
  41. parser.add_argument(
  42. "--skip-delete",
  43. action="store_true",
  44. help="Do not delete partitions.",
  45. required=False,
  46. default=False,
  47. )
  48. def handle( # type: ignore[override]
  49. self,
  50. dry: bool,
  51. yes: bool,
  52. using: Optional[str],
  53. skip_create: bool,
  54. skip_delete: bool,
  55. *args,
  56. **kwargs,
  57. ):
  58. partitioning_manager = self._partitioning_manager()
  59. plan = partitioning_manager.plan(
  60. skip_create=skip_create, skip_delete=skip_delete, using=using
  61. )
  62. creations_count = len(plan.creations)
  63. deletions_count = len(plan.deletions)
  64. if creations_count == 0 and deletions_count == 0:
  65. print("Nothing to be done.")
  66. return
  67. plan.print()
  68. if dry:
  69. return
  70. if not yes:
  71. sys.stdout.write("Do you want to proceed? (y/N) ")
  72. if not self._ask_for_confirmation():
  73. print("Operation aborted.")
  74. return
  75. plan.apply(using=using)
  76. print("Operations applied.")
  77. @staticmethod
  78. def _ask_for_confirmation() -> bool:
  79. answer = input("").lower()
  80. if not answer:
  81. return False
  82. if answer[0] == "y" or answer == "yes":
  83. return True
  84. return False
  85. @staticmethod
  86. def _partitioning_manager():
  87. partitioning_manager = getattr(
  88. settings, "PSQLEXTRA_PARTITIONING_MANAGER", None
  89. )
  90. if not partitioning_manager:
  91. raise PostgresPartitioningError(
  92. "You must configure the PSQLEXTRA_PARTITIONING_MANAGER setting "
  93. "for automatic partitioning to work."
  94. )
  95. if isinstance(partitioning_manager, str):
  96. partitioning_manager = import_string(partitioning_manager)
  97. return partitioning_manager