Plain is headed towards 1.0! Subscribe for development updates →

  1from plain.urls import path, reverse_lazy
  2
  3
  4class AdminViewRegistry:
  5    def __init__(self):
  6        # View classes that will be added to the admin automatically
  7        self.registered_views = set()
  8
  9    def register_view(self, view=None):
 10        def inner(view):
 11            self.registered_views.add(view)
 12            # TODO do this somewhere else...
 13            # self.registered_views = set(self.registered_views, key=lambda v: v.title)
 14            return view
 15
 16        if callable(view):
 17            return inner(view)
 18        else:
 19            return inner
 20
 21    def register_viewset(self, viewset=None):
 22        def inner(viewset):
 23            for view in viewset.get_views():
 24                self.register_view(view)
 25            return viewset
 26
 27        if callable(viewset):
 28            return inner(viewset)
 29        else:
 30            return inner
 31
 32    def get_nav_sections(self):
 33        # class NavItem:
 34        #     def __init__(self, view, children):
 35        #         self.view = view
 36        #         self.children = children
 37
 38        sections = {}
 39
 40        for view in self.registered_views:
 41            section = view.get_nav_section()
 42            if not section:
 43                continue
 44            if section not in sections:
 45                sections[section] = []
 46            sections[section].append(view)
 47
 48        # Sort each section by nav_title
 49        for section in sections.values():
 50            section.sort(key=lambda v: v.get_nav_title())
 51
 52        # Sort sections dictionary by key
 53        sections = dict(sorted(sections.items()))
 54
 55        return sections
 56
 57        # root_nav_items = []
 58
 59        # for view in sorted_views:
 60        #     if view.parent_view_class:
 61        #         continue
 62        #     children = [x for x in sorted_views if x.parent_view_class == view]
 63        #     root_nav_items.append(NavItem(view, children))
 64
 65        # return root_nav_items
 66
 67    def get_urls(self):
 68        urls = []
 69
 70        paths_seen = {}
 71
 72        for view in self.registered_views:
 73            view_path = view.get_path()
 74
 75            if not view_path:
 76                raise ValueError(f"Path for {view} is empty")
 77
 78            if existing_view := paths_seen.get(view_path, None):
 79                raise ValueError(
 80                    f"Duplicate admin path {view_path}\n{existing_view}\n{view}"
 81                )
 82
 83            paths_seen[view_path] = view
 84
 85            # Append trailing slashes automatically
 86            if not view_path.endswith("/"):
 87                view_path += "/"
 88
 89            urls.append(path(f"p/{view_path}", view, name=view.view_name()))
 90
 91        return urls
 92
 93    def get_searchable_views(self):
 94        views = [
 95            view
 96            for view in self.registered_views
 97            if getattr(view, "allow_global_search", False)
 98        ]
 99        # Sort by slug since title isn't required by all views
100        views.sort(key=lambda v: v.get_slug())
101        return views
102
103    def get_model_detail_url(self, instance):
104        from plain.admin.views.base import URL_NAMESPACE
105        from plain.admin.views.models import AdminModelDetailView
106
107        if not getattr(instance, "pk", None):
108            # Has to actually be in the db
109            return
110
111        for view in self.registered_views:
112            if not issubclass(view, AdminModelDetailView):
113                continue
114
115            if view.model == instance.__class__:
116                return reverse_lazy(
117                    f"{URL_NAMESPACE}:{view.view_name()}",
118                    pk=instance.pk,
119                )
120
121
122registry = AdminViewRegistry()
123register_view = registry.register_view
124register_viewset = registry.register_viewset
125get_model_detail_url = registry.get_model_detail_url