123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- import functools
- from collections import namedtuple
- def make_model_tuple(model):
- """
- Take a model or a string of the form "app_label.ModelName" and return a
- corresponding ("app_label", "modelname") tuple. If a tuple is passed in,
- assume it's a valid model tuple already and return it unchanged.
- """
- try:
- if isinstance(model, tuple):
- model_tuple = model
- elif isinstance(model, str):
- app_label, model_name = model.split(".")
- model_tuple = app_label, model_name.lower()
- else:
- model_tuple = model._meta.app_label, model._meta.model_name
- assert len(model_tuple) == 2
- return model_tuple
- except (ValueError, AssertionError):
- raise ValueError(
- "Invalid model reference '%s'. String model references "
- "must be of the form 'app_label.ModelName'." % model
- )
- def resolve_callables(mapping):
- """
- Generate key/value pairs for the given mapping where the values are
- evaluated if they're callable.
- """
- for k, v in mapping.items():
- yield k, v() if callable(v) else v
- def unpickle_named_row(names, values):
- return create_namedtuple_class(*names)(*values)
- @functools.lru_cache
- def create_namedtuple_class(*names):
- # Cache type() with @lru_cache since it's too slow to be called for every
- # QuerySet evaluation.
- def __reduce__(self):
- return unpickle_named_row, (names, tuple(self))
- return type(
- "Row",
- (namedtuple("Row", names),),
- {"__reduce__": __reduce__, "__slots__": ()},
- )
- class AltersData:
- """
- Make subclasses preserve the alters_data attribute on overridden methods.
- """
- def __init_subclass__(cls, **kwargs):
- for fn_name, fn in vars(cls).items():
- if callable(fn) and not hasattr(fn, "alters_data"):
- for base in cls.__bases__:
- if base_fn := getattr(base, fn_name, None):
- if hasattr(base_fn, "alters_data"):
- fn.alters_data = base_fn.alters_data
- break
- super().__init_subclass__(**kwargs)
|