"""Various utility functions for the dynamic_models app.""" import datetime from contextlib import contextmanager from django.db import connection from django.conf import settings from django.apps import apps from django.core.cache import cache from django.core.exceptions import FieldDoesNotExist from dynamic_models import config def db_table_exists(table_name): """Checks if the table name exists in the database.""" with _db_cursor() as c: table_names = connection.introspection.table_names(c) return table_name in table_names def db_table_has_field(table_name, field_name): """Checks if the table has a given field.""" table = _get_table_description(table_name) return field_name in [field.name for field in table] def db_field_allows_null(table_name, field_name): table_description = _get_table_description(table_name) for field in table_description: if field.name == field_name: return field.null_ok raise FieldDoesNotExist(f'field {field_name} does not exist on table {table_name}') def _get_table_description(table_name): with _db_cursor() as c: return connection.introspection.get_table_description(c, table_name) @contextmanager def _db_cursor(): """Create a database cursor and close it on exit.""" cursor = connection.cursor() yield cursor cursor.close() def receiver_is_connected(receiver_name, signal, sender): receivers = signal._live_receivers(sender) receiver_strings = [ "{}.{}".format(r.__module__, r.__name__) for r in receivers ] return receiver_name in receiver_strings class LastModifiedCache: def cache_key(self, model_schema): return config.cache_key_prefix() + model_schema.db_table def get(self, model_schema): """Return the last time of modification or the max date value.""" max_date = datetime.datetime.max if settings.USE_TZ: max_date = max_date.replace(tzinfo=datetime.timezone.utc) return cache.get(self.cache_key(model_schema), max_date) def set(self, model_schema, timestamp, timeout=config.cache_timeout()): cache.set(self.cache_key(model_schema), timestamp, timeout) def delete(self, model_schema): cache.delete(self.cache_key(model_schema)) class ModelRegistry: def __init__(self, app_label): self.app_label = app_label def is_registered(self, model_name): return model_name.lower() in apps.all_models[self.app_label] def get_model(self, model_name): try: return apps.get_model(self.app_label, model_name) except LookupError: return None def unregister_model(self, model_name): try: del apps.all_models[self.app_label][model_name.lower()] except KeyError as err: raise LookupError("'{}' not found.".format(model_name)) from err