Как использовать пользовательский класс AdminSite?

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

26
задан Louis 5 May 2015 в 14:48
поделиться

3 ответа

Цитата из https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#customizing-the-adminsite-class

Если вы Вы хотите настроить свой собственный административный сайт с настраиваемым поведением, однако вы можете создавать подклассы AdminSite и переопределять или добавлять все, что вам нравится. Затем просто создайте экземпляр вашего подкласса AdminSite (так же, как вы создаете экземпляр любого другого класса Python), и зарегистрируйте в нем свои модели и подклассы ModelAdmin вместо использования по умолчанию .

Я полагаю, что это наиболее явный подход, но это также означает, что вам нужно изменить код регистра в файлах admin.py приложений.

На самом деле нет необходимости использовать автообнаружение при использовании собственного экземпляра AdminSite, так как вы, вероятно, будете импортировать все модули admin.py для приложения в свой модуль myproject.admin.

Предполагается, что, как только вы начинаете писать свой собственный сайт администратора, он становится в значительной степени специфичным для проекта, и вы заранее знаете, какие приложения вы хотите включить.

Так что если вы не хотите работать с хаком выше, я действительно вижу только эти два варианта. Замените все зарегистрированные вызовы на свой пользовательский сайт администратора или зарегистрируйте модели явно в модуле администратора.

6
ответ дан ruddra 5 May 2015 в 14:48
поделиться

В Django 2.1 существует готовое решение: https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#overriding-the-default. -admin-site

from django.contrib import admin

class MyAdminSite(admin.AdminSite):
...

Замена пользовательского сайта администратора теперь выполняется путем добавления собственного AdminConfig в установленные приложения.

from django.contrib.admin.apps import AdminConfig

class MyAdminConfig(AdminConfig):
    default_site = 'myproject.admin.MyAdminSite'


INSTALLED_APPS = [
    ...
    'myproject.apps.MyAdminConfig',  # replaces 'django.contrib.admin'
    ...
]

Обратите внимание на разницу между AdminConfig и SimpleAdminConfig, где последний не срабатывает admin.autodiscover(). В настоящее время я использую это решение в проекте.

4
ответ дан Elwin 5 May 2015 в 14:48
поделиться

Проблема

Использование пользовательского класса, полученного из django.contrib.admin.AdminSite для сайта администратора проекта, без необходимости написания пользовательского регистрационного кода для регистрации моделей в новом классе. Когда я использую сторонние приложения с их собственными моделями, я бы не стал редактировать пользовательский регистрационный код только потому, что модели были добавлены или удалены из этих приложений.

Решение

Вы должны переключить экземпляр, созданный с помощью класса по умолчанию, используемого для сайта администратора, на свой собственный экземпляр, созданный с вашим собственным классом до django.contrib.admin 'autodiscover функция вызывается. Я делаю это:

  1. Наличие приложения, которое будет выполнять переключение. (Я использую свое приложение для конкретного проекта под названием core для своих собственных целей.)

  2. Два варианта:

    1. Django 1.6 до 1.9: Используйте __init__ приложения для выполнения переключения. В Django 1.8 вы получите предупреждение об устаревании из-за изменений в Django 1.9, указанных ниже. Обратите внимание, что этот метод будет работать также с 1.9, потому что модули Django, загруженные с помощью кода, показанного ниже, были изменены в 1.9, чтобы они больше не загружали модели. Когда я использую этот метод, мой core/__init__.py файл содержит:

      from django.contrib import admin
      from django.contrib.admin import sites
      
      class MyAdminSite(admin.AdminSite):
          pass
      
      mysite = MyAdminSite()
      admin.site = mysite
      sites.site = mysite
      
    2. Django 1.9 и более: использует конфигурацию приложения приложения для выполнения переключения. Начиная с Django 1.9, в примечаниях к выпуску говорится :

      Все модели должны быть определены внутри установленного приложения или объявлены явные метки app_label. Кроме того, невозможно импортировать их до загрузки их приложения. В частности, невозможно импортировать модели внутри корневого пакета приложения.

      Я предпочитаю ограничивать импорт, который я делаю на корневом уровне, чтобы избежать риска загрузки моделей. В то время как в версии 1.9 с использованием метода __init__, описанного выше, будет работать , невозможно сказать, будет ли 1.10 или более поздняя версия вносить изменения, которые вызовут проблемы.

      Когда я использую этот метод, core/__init__.py устанавливает default_app_config = "core.apps.DefaultAppConfig", и у меня есть core/apps.py, подобный этому:

      from django.apps import AppConfig
      
      class DefaultAppConfig(AppConfig):
          name = 'core'
      
          def ready(self):
              from django.contrib import admin
              from django.contrib.admin import sites
      
              class MyAdminSite(admin.AdminSite):
                  pass
      
              mysite = MyAdminSite()
              admin.site = mysite
              sites.site = mysite
      

      Хотя этот метод можно использовать с версиями 1.7 и 1.8, он немного рискованно использовать его с этими версиями. См. Примечания ниже.

  3. Размещение этого приложения раньше, чем , чем django.contrib.admin, в списке INSTALLED_APPS. (Это абсолютно необходимо для 1.7 и более поздних версий. В более ранних версиях Django он мог бы работать нормально, даже если приложение более позднее, чем django.contrib.admin. Однако см. Примечания ниже.)

Примечания и предостережения

  • Приложение, которое выполняет переключение, должно действительно быть первым приложением в списке INSTALLED_APPS, чтобы минимизировать вероятность того, что что-то еще получит значение site из django.contrib.admin до того, как будет выполнено переключение. Если другому приложению удастся получить это значение до того, как будет выполнено переключение, то у этого другого приложения будет ссылка на старый сайт. Веселье наверняка наступит.

  • Приведенный выше метод не будет работать хорошо, если два приложения пытаются установить свой собственный новый класс сайта администратора по умолчанию. Это должно быть обработано на индивидуальной основе.

  • Вполне возможно, что будущий релиз Django может сломать этот метод.

  • Для версии до 1.9 я предпочел использовать __init__ для переключения сайтов с использованием конфигурации приложения, поскольку документация об инициализации указывает, что метод ready() конфигураций приложения называется относительно поздно. Между моментом загрузки модуля приложения и вызовом ready() моделей загружаются, и в некоторых случаях это может означать, что модуль получил значение site из django.contrib.admin до того, как ready называется. Чтобы минимизировать риск, у меня есть код приложения __init__ для переключения.

    Я полагаю, что риск, существовавший в версиях 1.7 и 1.8 и которого я избежал, используя __init__ для выполнения переключения сайта как можно раньше, не существует в 1.9. Всем запрещается загружать модули до загрузки всех приложений. Таким образом, переключение в обратном вызове ready первого приложения, указанного в INSTALLED_APPS, должно быть безопасным. Я обновил большой проект до 1.9 и без проблем использовал метод конфигурации приложения.

23
ответ дан Louis 5 May 2015 в 14:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: