Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.py 4.3KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import datetime
  2. import re
  3. from collections import namedtuple
  4. from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
  5. FieldReference = namedtuple("FieldReference", "to through")
  6. COMPILED_REGEX_TYPE = type(re.compile(""))
  7. class RegexObject:
  8. def __init__(self, obj):
  9. self.pattern = obj.pattern
  10. self.flags = obj.flags
  11. def __eq__(self, other):
  12. if not isinstance(other, RegexObject):
  13. return NotImplemented
  14. return self.pattern == other.pattern and self.flags == other.flags
  15. def get_migration_name_timestamp():
  16. return datetime.datetime.now().strftime("%Y%m%d_%H%M")
  17. def resolve_relation(model, app_label=None, model_name=None):
  18. """
  19. Turn a model class or model reference string and return a model tuple.
  20. app_label and model_name are used to resolve the scope of recursive and
  21. unscoped model relationship.
  22. """
  23. if isinstance(model, str):
  24. if model == RECURSIVE_RELATIONSHIP_CONSTANT:
  25. if app_label is None or model_name is None:
  26. raise TypeError(
  27. "app_label and model_name must be provided to resolve "
  28. "recursive relationships."
  29. )
  30. return app_label, model_name
  31. if "." in model:
  32. app_label, model_name = model.split(".", 1)
  33. return app_label, model_name.lower()
  34. if app_label is None:
  35. raise TypeError(
  36. "app_label must be provided to resolve unscoped model relationships."
  37. )
  38. return app_label, model.lower()
  39. return model._meta.app_label, model._meta.model_name
  40. def field_references(
  41. model_tuple,
  42. field,
  43. reference_model_tuple,
  44. reference_field_name=None,
  45. reference_field=None,
  46. ):
  47. """
  48. Return either False or a FieldReference if `field` references provided
  49. context.
  50. False positives can be returned if `reference_field_name` is provided
  51. without `reference_field` because of the introspection limitation it
  52. incurs. This should not be an issue when this function is used to determine
  53. whether or not an optimization can take place.
  54. """
  55. remote_field = field.remote_field
  56. if not remote_field:
  57. return False
  58. references_to = None
  59. references_through = None
  60. if resolve_relation(remote_field.model, *model_tuple) == reference_model_tuple:
  61. to_fields = getattr(field, "to_fields", None)
  62. if (
  63. reference_field_name is None
  64. or
  65. # Unspecified to_field(s).
  66. to_fields is None
  67. or
  68. # Reference to primary key.
  69. (
  70. None in to_fields
  71. and (reference_field is None or reference_field.primary_key)
  72. )
  73. or
  74. # Reference to field.
  75. reference_field_name in to_fields
  76. ):
  77. references_to = (remote_field, to_fields)
  78. through = getattr(remote_field, "through", None)
  79. if through and resolve_relation(through, *model_tuple) == reference_model_tuple:
  80. through_fields = remote_field.through_fields
  81. if (
  82. reference_field_name is None
  83. or
  84. # Unspecified through_fields.
  85. through_fields is None
  86. or
  87. # Reference to field.
  88. reference_field_name in through_fields
  89. ):
  90. references_through = (remote_field, through_fields)
  91. if not (references_to or references_through):
  92. return False
  93. return FieldReference(references_to, references_through)
  94. def get_references(state, model_tuple, field_tuple=()):
  95. """
  96. Generator of (model_state, name, field, reference) referencing
  97. provided context.
  98. If field_tuple is provided only references to this particular field of
  99. model_tuple will be generated.
  100. """
  101. for state_model_tuple, model_state in state.models.items():
  102. for name, field in model_state.fields.items():
  103. reference = field_references(
  104. state_model_tuple, field, model_tuple, *field_tuple
  105. )
  106. if reference:
  107. yield model_state, name, field, reference
  108. def field_is_referenced(state, model_tuple, field_tuple):
  109. """Return whether `field_tuple` is referenced by any state models."""
  110. return next(get_references(state, model_tuple, field_tuple), None) is not None