lazy_admin.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from __future__ import unicode_literals
  2. from django.conf import settings
  3. from django.conf.urls import include, url
  4. from django.contrib.auth import get_user_model
  5. from django.contrib.admin.sites import (AdminSite, site as default_site,
  6. NotRegistered, AlreadyRegistered)
  7. from django.shortcuts import redirect
  8. from mezzanine.utils.importing import import_dotted_path
  9. class LazyAdminSite(AdminSite):
  10. """
  11. Defers calls to register/unregister until autodiscover is called
  12. to avoid load issues with injectable model fields defined by
  13. ``settings.EXTRA_MODEL_FIELDS``.
  14. """
  15. def __init__(self, *args, **kwargs):
  16. self._deferred = []
  17. super(LazyAdminSite, self).__init__(*args, **kwargs)
  18. def register(self, *args, **kwargs):
  19. for name, deferred_args, deferred_kwargs in self._deferred:
  20. if name == "unregister" and deferred_args[0] == args[0]:
  21. self._deferred.append(("register", args, kwargs))
  22. break
  23. else:
  24. super(LazyAdminSite, self).register(*args, **kwargs)
  25. def unregister(self, *args, **kwargs):
  26. self._deferred.append(("unregister", args, kwargs))
  27. def lazy_registration(self):
  28. # First, directly handle models we don't want at all,
  29. # as per the ``ADMIN_REMOVAL`` setting.
  30. for model in getattr(settings, "ADMIN_REMOVAL", []):
  31. try:
  32. model = tuple(model.rsplit(".", 1))
  33. exec("from %s import %s" % model)
  34. except ImportError:
  35. pass
  36. else:
  37. try:
  38. AdminSite.unregister(self, eval(model[1]))
  39. except NotRegistered:
  40. pass
  41. # Pick up any admin classes registered via decorator to the
  42. # default admin site.
  43. for model, admin in default_site._registry.items():
  44. self._deferred.append(("register", (model, admin.__class__), {}))
  45. # Call register/unregister.
  46. for name, args, kwargs in self._deferred:
  47. try:
  48. getattr(AdminSite, name)(self, *args, **kwargs)
  49. except (AlreadyRegistered, NotRegistered):
  50. pass
  51. @property
  52. def urls(self):
  53. urls = [url("", super(LazyAdminSite, self).urls)]
  54. # Filebrowser admin media library.
  55. fb_name = getattr(settings, "PACKAGE_NAME_FILEBROWSER", "")
  56. if fb_name in settings.INSTALLED_APPS:
  57. try:
  58. fb_urls = import_dotted_path("%s.sites.site" % fb_name).urls
  59. except ImportError:
  60. fb_urls = "%s.urls" % fb_name
  61. urls = [
  62. # This gives the media library a root URL (which filebrowser
  63. # doesn't provide), so that we can target it in the
  64. # ADMIN_MENU_ORDER setting, allowing each view to correctly
  65. # highlight its left-hand admin nav item.
  66. url("^media-library/$", lambda r: redirect("fb_browse"),
  67. name="media-library"),
  68. url("^media-library/", include(fb_urls)),
  69. ] + urls
  70. # Give the urlpattern for the user password change view an
  71. # actual name, so that it can be reversed with multiple
  72. # languages are supported in the admin.
  73. User = get_user_model()
  74. for admin in self._registry.values():
  75. user_change_password = getattr(admin, "user_change_password", None)
  76. if user_change_password:
  77. bits = (User._meta.app_label, User._meta.object_name.lower())
  78. urls = [
  79. url("^%s/%s/(\d+)/password/$" % bits,
  80. self.admin_view(user_change_password),
  81. name="user_change_password"),
  82. ] + urls
  83. break
  84. # Misc Mezzanine urlpatterns that should reside under /admin/ url,
  85. # specifically for compatibility with SSLRedirectMiddleware.
  86. from mezzanine.core.views import displayable_links_js, static_proxy
  87. from mezzanine.generic.views import admin_keywords_submit
  88. urls += [
  89. url("^admin_keywords_submit/$", admin_keywords_submit,
  90. name="admin_keywords_submit"),
  91. url("^asset_proxy/$", static_proxy, name="static_proxy"),
  92. url("^displayable_links.js$", displayable_links_js,
  93. name="displayable_links_js"),
  94. ]
  95. if "mezzanine.pages" in settings.INSTALLED_APPS:
  96. from mezzanine.pages.views import admin_page_ordering
  97. urls.append(url("^admin_page_ordering/$", admin_page_ordering,
  98. name="admin_page_ordering"))
  99. return urls