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, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Цитата из 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.
Предполагается, что, как только вы начинаете писать свой собственный сайт администратора, он становится в значительной степени специфичным для проекта, и вы заранее знаете, какие приложения вы хотите включить.
Так что если вы не хотите работать с хаком выше, я действительно вижу только эти два варианта. Замените все зарегистрированные вызовы на свой пользовательский сайт администратора или зарегистрируйте модели явно в модуле администратора.
В 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()
. В настоящее время я использую это решение в проекте.
Использование пользовательского класса, полученного из django.contrib.admin.AdminSite
для сайта администратора проекта, без необходимости написания пользовательского регистрационного кода для регистрации моделей в новом классе. Когда я использую сторонние приложения с их собственными моделями, я бы не стал редактировать пользовательский регистрационный код только потому, что модели были добавлены или удалены из этих приложений.
Вы должны переключить экземпляр, созданный с помощью класса по умолчанию, используемого для сайта администратора, на свой собственный экземпляр, созданный с вашим собственным классом до django.contrib.admin
'autodiscover
функция вызывается. Я делаю это:
Наличие приложения, которое будет выполнять переключение. (Я использую свое приложение для конкретного проекта под названием core
для своих собственных целей.)
Два варианта:
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
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, он немного рискованно использовать его с этими версиями. См. Примечания ниже.
Размещение этого приложения раньше, чем , чем 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 и без проблем использовал метод конфигурации приложения.