Исходный код для django.apps.registry

импорт  functools 
IMPORT  SYS 
импорт  пронизывающий 
импорт  предупреждения 
из  коллекций  импорта  счетчика ,  defaultdict 
из  functools  импорта  частичного

от  django.core.exceptions  импорта  AppRegistryNotReady ,  ImproperlyConfigured

из  .config  импортировать  AppConfig


class  Apps : 
    "" " 
    Реестр, в котором хранится конфигурация установленных приложений.

    Он также отслеживает модели, например, для обеспечения обратных отношений. 
    «»»

    def  __init__ ( self ,  installed_apps = ()): 
        # installed_apps установлено значение None при создании главного реестра 
        #, потому что он не может быть заполнен в этот момент. Другие реестры должны 
        # предоставить список установленных приложений и сразу же заполнить их. 
        если значение  installed_apps  равно  None,  а  hasattr ( sys . modules [ __name__ ],  'apps' ): 
            поднять  RuntimeError ( "Вы должны указать аргумент installed_apps." )

        # Сопоставление меток приложений => имена моделей => классы моделей. Каждый раз, когда 
        модель импортируется, ModelBase .__ new__ вызывает apps.register_model, который 
        # создает запись в all_models. Все импортированные модели регистрируются, 
        # независимо от того, определены ли они в установленном приложении 
        # и заполнен ли реестр. Поскольку невозможно 
        # безопасно повторно 
        импортировать 
        модуль (это может повторно выполнить код инициализации) # all_models никогда не переопределяется и не сбрасывается. я . all_models  =  defaultdict ( ДИКТ )

        # Сопоставление меток с экземплярами AppConfig для установленных приложений. 
        я . app_configs  =  {}

        # Стек app_configs. Используется для хранения текущего состояния в 
        # set_available_apps и set_installed_apps. 
        я . stored_app_configs  =  []

        # Заполнен ли реестр. 
        я . apps_ready  =  сам . models_ready  =  сам . ready  =  False 
        # Для автозагрузчика. 
        я . ready_event  =  потоки . Событие ()

        # Блокировка для потокобезопасного заполнения. 
        я . _lock  =  потоки . RLock () 
        самостоятельно . loading  =  False

        # Сопоставляет ("app_label", "modelname") кортежи со списками функций, которые 
        # 
        будут вызываться, когда соответствующая модель будет готова. Используется методами этого класса # `lazy_model_operation ()` и `do_pending_operations ()`. 
        я . _pending_operations  =  defaultdict ( список )

        # Заполните приложения и модели, если это не главный реестр. 
        если значение  installed_apps  не равно  None : self . заполнить ( установленные_приложения ) 
            

    def  populate ( self ,  installed_apps = None ): 
        "" " 
        Загрузить конфигурации и модели приложений.

        Импортируйте каждый модуль приложения, а затем каждый модуль модели.

        Он потокобезопасный и идемпотентный, но не реентерабельный. 
        «»» 
        Если  самостоятельно . Готов : 
            возвращение

        # populate () может вызываться двумя потоками параллельно на серверах 
        #, которые создают потоки перед инициализацией вызываемого WSGI. 
        с  собой . _lock : 
            если  self . готово : 
                вернуться

            # RLock предотвращает вход других потоков в этот раздел. Операция 
            сравнения и установки # ниже является атомарной. 
            если  сам . loading : 
                # Предотвратить повторные вызовы, чтобы не запускать 
                методы 
                AppConfig.ready () # дважды. поднять  RuntimeError ( " populate ( ) не реентерабельно" ) 
            self . loading  =  True

            # Этап 1: инициализация конфигураций приложения и импорт модулей приложения. 
            для  записи  в  installed_apps : 
                if  isinstance ( entry ,  AppConfig ): 
                    app_config  =  entry 
                else : 
                    app_config  =  AppConfig . создать ( запись ), 
                если  app_config . ярлык  в  себе . app_configs : 
                    повышение  ImproperlyConfigured ( 
                        "ярлыки приложений не являются уникальными," 
                        "дубликатами: % S "  % app_config . этикетка )

                я . app_configs [ app_config . label ]  =  app_config 
                app_config . apps  =  self

            # Проверить повторяющиеся имена приложений. 
            counts  =  Counter ( 
                app_config . name  for  app_config  в  self . app_configs . values ()) 
            duplicates  =  [ 
                name  for  name ,  count  in  counts . most_common ()  if  count  >  1 ] 
            if  duplicates : 
                raise  ImproperlyConfigured ( 
                    «Имена приложений не уникальны», 
                    «duplicates: % s »  % "," . присоединиться ( дубликаты ))

            я . apps_ready  =  Правда

            # Этап 2: импорт модулей моделей. 
            для  app_config  в  себе . app_configs . values (): 
                app_config . import_models ()

            я . clear_cache ()

            я . models_ready  =  Верно

            # Этап 3: запуск методов ready () конфигураций приложений. 
            для  app_config  в  себе . get_app_configs (): 
                app_config . готов ()

            я . готов  =  Истинную 
            себя . ready_event . набор ()

    def  check_apps_ready ( self ): 
        "" " 
        Вызвать исключение, если все приложения еще не импортированы." "" если  не  self . apps_ready : 
            от  django.conf  Импорта  Настройки 
            # Если «не готовы» из - за неконфигурированные настройки доступа 
            # INSTALLED_APPS поднимает более полезный ImproperlyConfigured 
            # исключения. 
            настройки . INSTALLED_APPS 
            поднять  AppRegistryNotReady ( «Приложения еще не загружены» ).

    def  check_models_ready ( self ): 
        "" " 
        Вызвать исключение, если все модели еще не импортированы." "" если  не  self . models_ready : 
            поднять  AppRegistryNotReady ( «Модели еще не загружены.» )

    def  get_app_configs ( self ): 
        "" "Импортировать приложения и возвращать итерацию конфигураций приложений." "" 
        self . check_apps_ready () 
        вернуть  себя . app_configs . значения ()

    def  get_app_config ( self ,  app_label ): 
        "" " 
        Импортировать приложения и возвращает конфигурацию приложения для данной метки.

        Поднимите LookupError, если приложение с этой меткой не существует. 
        "" " 
        self . check_apps_ready () 
        try : 
            return  self . app_configs [ app_label ] 
        except  KeyError : 
            message  =  " Не установлено приложение с меткой ' % s '. "  %  app_label 
            для  app_config  в  self . get_app_configs (): 
                if  app_config . name  = =  app_label : 
                    message  + =  "Возможно, вы имели в виду" % s'? "  %  app_config . label 
                    break 
            вызывать  LookupError ( сообщение )

    # Этот метод критичен к производительности, по крайней мере, для набора тестов Django. 
    @functools . lru_cache ( maxsize = None ) 
    def  get_models ( self ,  include_auto_created = False ,  include_swapped = False ): 
        "" " 
        Возвращает список всех установленных моделей.

        По умолчанию следующие модели не включены:

        - автоматически созданные модели для отношений «многие ко многим» без 
          явной промежуточной таблицы, 
        - модели, которые были заменены местами.

        Задайте для соответствующего аргумента ключевого слова значение True, чтобы включить такие модели. 
        "" " 
        self . check_models_ready ()

        result  =  [] 
        для  app_config  в  себе . app_configs . values (): 
            результат . extend ( app_config . get_models ( include_auto_created ,  include_swapped )) 
        вернуть  результат

    def  get_model ( self ,  app_label ,  model_name = None ,  require_ready = True ): 
        "" " 
        Возвращает модель, соответствующую указанным app_label и model_name.

        В качестве ярлыка app_label может иметь форму <app_label>. <model_name>.

        имя_модели не чувствительно к регистру.

        Поднимите LookupError, если приложение с этой меткой не 
        существует 
или в приложении не существует модели с таким именем. Поднимите ValueError, если         вызывается с одним аргументом, который не содержит ровно одной точки. 
        "" " 
        если  require_ready : 
            self . check_models_ready () 
        else : 
            self . check_apps_ready ()

        если  имя_модели  -  Нет : 
            app_label ,  model_name  =  app_label . разделить ( '.' )

        app_config  =  себя . get_app_config ( app_label )

        если  не  require_ready  и  app_config . модели  является  None : 
            app_config . import_models ()

        вернуть  app_config . get_model ( имя_модели ,  require_ready = require_ready )

    def  register_model ( self ,  app_label ,  model ): 
        # Поскольку этот метод вызывается при импорте моделей, он не может 
        # выполнять импорт из-за риска возникновения циклов импорта. Он не должен 
        # вызывать get_app_config (). 
        model_name  =  модель . _meta . имя_модели 
        app_models  =  self . all_models [ app_label ] 
        if  model_name  в  app_models : 
            if  ( model . __name__  ==  app_models [имя_модели ] . __name__  и 
                    модель . __module__  ==  app_models [ название_модели ] . __module__ ): 
                предупреждения . warn ( 
                    «Модель ' % s . % s ' уже была зарегистрирована.» 
                    «Перезагрузка моделей не рекомендуется, так как это может привести к несогласованности» 
                    «особенно со связанными моделями.»  %  ( app_label ,  model_name ), 
                    RuntimeWarning ,  stacklevel = 2 ) 
            else : 
                поднять RuntimeError ( 
                    "Конфликт моделей ' % s ' в приложении ' % s ': % s и % s ."  % 
                    ( Model_name ,  app_label ,  app_models [ model_name ],  model )) 
        app_models [ model_name ]  =  model 
        self . do_pending_operations ( модель ) 
        self . clear_cache ()

    def  is_installed ( self ,  app_name ): 
        "" " 
        Проверить, существует ли приложение с этим именем в реестре.

        app_name - это полное имя приложения, например django.contrib.admin. 
        "" " 
        self . check_apps_ready () 
        вернуть  любое ( ac . name  ==  app_name  для  ac  в  self . app_configs . values ())

    def  get_contain_app_config ( self ,  object_name ): 
        "" " 
        Найдите конфигурацию приложения, содержащую данный объект.

        object_name - это путь Python к объекту, обозначенный точками.

        Вернуть конфигурацию приложения для внутреннего приложения в случае вложенности. 
        Верните None, если объект отсутствует в зарегистрированной конфигурации приложения. 
        "" " 
        self . check_apps_ready () 
        кандидаты  =  [] 
        для  app_config  в  self . app_configs . values (): 
            если  имя_объекта . начинается с ( app_config . name ): 
                subpath  =  object_name [ len ( app_config . name ):] 
                if  subpath  == ''  или  подпуть [ 0 ]  ==  '.' : 
                    кандидаты . добавить ( app_config ), 
        если  кандидаты : 
            вернуть  отсортированные ( кандидаты ,  ключ = лямбда  ac :  - len ( ac . name )) [ 0 ]

    def  get_registered_model ( self ,  app_label ,  model_name ): 
        "" " 
        Подобно get_model (), но не требует наличия приложения с 
        данным app_label.

        Этот метод можно безопасно вызывать во время импорта, даже когда реестр 
        заполняется. 
        "" " 
        model  =  self . all_models [ app_label ] . get ( model_name . lower ()) 
        if  model  is  None : 
            raise  LookupError ( 
                " Модель ' % s . % s ' не зарегистрирована. "  %  ( app_label ,  model_name )) 
        return  model

    @functools . lru_cache ( maxsize = None ) 
    def  get_swappable_settings_name ( self ,  to_string ): 
        "" " 
        Для заданной строки модели (например," auth.User ") вернуть имя 
        соответствующего имени настройки, если оно относится к заменяемой модели. Если 
        указанная модель не подлежит замене, вернуть None.

        Этот метод украшен lru_cache, потому что он 
        критически важен для 
производительности при миграции. Поскольку заменяемые настройки не         меняются после того, как Django загрузил настройки, нет причин получать 
        соответствующий атрибут настроек снова и снова. 
        «»» 
        Для  модели  в  себе . Get_models ( include_swapped = Правда ): 
            поменять местами  =  модель . _Meta . Местами 
            # эта модель выгружена для модели , заданной to_string? 
            Если  поменять местами  и  местами  ==  to_string: 
                вернуть  модель . _meta . swappable 
            # Можно ли поменять эту модель и модель, заданную to_string? 
            если  модель . _meta . заменяемый  и  модель . _meta . label  ==  to_string : 
                вернуть  модель . _meta . заменяемый 
        возврат  Нет

    def  set_available_apps ( self ,  available ): 
        "" " 
        Ограничить набор установленных приложений, используемых get_app_config [s].

        available должен быть повторяющимся именами приложений.

        set_available_apps () должен быть сбалансирован с unset_available_apps ().

        В основном используется для оптимизации производительности в TransactionTestCase.

        Этот метод безопасен в том смысле, что не запускает импорт. 
        «» « 
        Доступно  =  набор ( доступно ) 
        установлено  =  { app_config . Имя  для  app_config  в  себе . Get_app_configs ()} 
        если  не  доступны . Issubset ( установлено ): 
            Raise  ValueError ( 
                » Доступные приложения не является подмножество установленных приложений, дополнительных приложения : % s " 
                %  ", " . join ( доступно  - установлен ) 
            )

        я . сохранено_app_configs . добавить ( self . app_configs ) 
        self . app_configs  =  { 
            label :  app_config 
            для  ярлыка ,  app_config  в  себе . app_configs . items (), 
            если  app_config . имя  в  наличии 
        } 
        я . clear_cache ()

    def  unset_available_apps ( self ): 
        "" "Отменить предыдущий вызов set_available_apps ()." "" 
        self . app_configs  =  себя . сохранено_app_configs . pop () 
        self . clear_cache ()

    def  set_installed_apps ( self ,  installed ): 
        "" " 
        Включить другой набор установленных приложений для get_app_config [s].

        установленный должен быть итеративным в том же формате, что и INSTALLED_APPS.

        set_installed_apps () должен быть сбалансирован с unset_installed_apps (), 
        даже если он завершается с исключением.

        В основном используется как приемник сигнала setting_changed в тестах.

        Этот метод может запускать новый импорт, который может добавлять новые модели в 
        реестр всех импортированных моделей. Они останутся в реестре даже 
        после unset_installed_apps (). Поскольку невозможно 
        безопасно 
воспроизвести импорт (например, это может привести к двойной регистрации слушателей),         модели регистрируются при импорте и никогда не удаляются. 
        "" " 
        если  не  self . ready : 
            поднять  AppRegistryNotReady ( " Реестр приложений еще не готов. " ) 
        self . stored_app_configs . append ( self . app_configs )
        я . app_configs  =  {} 
        сам . apps_ready  =  сам . models_ready  =  сам . загрузка  =  сам . готов  =  ложных 
        себя . clear_cache () 
        самостоятельно . заполнить ( установлено )

    def  unset_installed_apps ( self ): 
        "" "Отменить предыдущий вызов set_installed_apps ()." "" 
        self . app_configs  =  себя . сохранено_app_configs . pop () 
        self . apps_ready  =  сам . models_ready  =  сам . готов  =  Истинную 
        себя . clear_cache ()

    def  clear_cache ( self ): 
        "" " 
        Очистить все внутренние кеши для методов, изменяющих реестр приложения.

        В основном это используется в тестах. 
        "" " 
        # Вызов истекает кеш для каждой модели. Это очистит 
        # дерево отношений и кеш полей. 
        Self . Get_models . Cache_clear () 
        if  self . Ready : 
            # Обойти self.get_models (), чтобы предотвратить переполнение кеша. 
            #. это , в частности , что предотвращает пустое значение кэшируется при клонировании 
            для  app_config  в  собственной . app_configs . значения (): 
                для  модели  в  app_config . get_models ( include_auto_created= True ): 
                    модель . _meta . _expire_cache ()

    def  lazy_model_operation ( self ,  function ,  * model_keys ): 
        "" " 
        Возьмите функцию и несколько кортежей (" app_label "," modelname "), и 
        когда все соответствующие модели будут импортированы и зарегистрированы, 
        вызовите функцию с моделью классы в качестве аргументов.

        Функция, переданная этому методу, должна принимать ровно n моделей в качестве 
        аргументов, где n = len (model_keys). 
        "" " 
        # Базовый случай: без аргументов, просто выполните функцию. 
        Если  не  model_keys : 
            function () 
        # Рекурсивный случай: возьмите заголовок model_keys, дождитесь 
        # импорта и регистрации соответствующего класса модели, затем примените 
        # этот аргумент в предоставленную функцию. Передайте полученный частичный 
        # в lazy_model_operation () вместе с оставшимися аргументами модели и 
        # повторяйте, пока все модели не будут загружены и все аргументы не будут применены. 
        else : 
            next_model ,  * more_models  = model_keys

            # Это будет выполнено после того, как класс, соответствующий next_model 
            #, будет импортирован и зарегистрирован. Атрибут `func` обеспечивает 
            совместимость # типа утки с партиалами. 
            def  apply_next_model ( модель ): 
                next_function  =  partial ( apply_next_model . func ,  model ) 
                self . lazy_model_operation ( next_function ,  * more_models ) 
            apply_next_model . func  =  функция

            # Если модель уже была импортирована и зарегистрирована, частично 
            примените ее к функции сейчас. Если нет, добавьте его в список 
            ожидающих # операций для модели, где он будет выполняться с 
            # классом модели в качестве единственного аргумента, как только модель будет готова. 
            попробуйте : 
                model_class  =  self . get_registered_model ( * next_model ), 
            кроме  LookupError : 
                self . _nding_operations [ следующая_модель ] . append ( apply_next_model ) 
            else : 
                apply_next_model (model_class )

    def  do_pending_operations ( self ,  model ): 
        "" " 
        Возьмите только что подготовленную модель и передайте ее каждой ожидающей 
        ее функции. Это вызывается в самом конце Apps.register_model (). 
        " "" 
        key  =  model . _meta . app_label ,  модель . _meta . имя_модели 
        для  функции  в  себе . _pending_operations . pop ( key ,  []): 
            функция ( модель )


apps  =  Приложения ( installed_apps = Нет )

Copyright ©2021 All rights reserved