Как создать apphooks

apphook позволяет вам прикрепить Django-приложение к странице. Например, у вас может быть новостное приложение, которое вы хотели бы интегрировать с django CMS. В этом случае вы можете создать обычную страницу django CMS без собственного содержимого и прикрепить новостное приложение к этой странице; содержимое новостного приложения будет доставлено по URL страницы.

Все URL-адреса в этом пути URL будут переданы в URL-конфигурации подключенного приложения.

Раздел Tutorials содержит базовое руководство по getting started with apphooks. Этот документ предполагает большее знакомство с CMS в целом.

Основы создания apphook

Чтобы создать apphook, создайте файл cms_apps.py в вашем приложении.

Файл должен содержать подкласс CMSApp. Например:

from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool

@apphook_pool.register
class MyApphook(CMSApp):
    app_name = "myapp"  # must match the application namespace
    name = "My Apphook"

    def get_urls(self, page=None, language=None, **kwargs):
        return ["myapp.urls"] # replace this with the path to your application's URLs module

Изменено в версии 3.3: CMSApp.get_urls() заменяет CMSApp.urls. urls был удален в версии 3.5.

Apphooks для приложений с разграничением имен

Ваше приложение должно использовать namespaced URLs.

В приведенном выше примере приложение использует пространство имен myapp. Ваш подкласс CMSApp должен отражать пространство имен приложения в атрибуте app_name.

Приложение может указать пространство имен, поставив app_name в своем urls.py, или его документация может рекомендовать, чтобы вы, когда включаете его URL, делали это таким образом:

re_path(r'^myapp/', include('myapp.urls', app_name='myapp'))

Если этого не сделать, то все шаблоны в приложении, вызывающие URL с помощью формы {% url 'myapp:index' %} или представления, вызывающие (например) reverse('myapp:index'), будут выдавать ошибку NoReverseMatch.

Apphooks для неименованных приложений

Если вы пишете apphooks для сторонних приложений, вы можете встретить такое приложение, которое фактически не имеет пространства имен приложения для своих URL. Такое приложение может быть подвержено конфликтам пространств имен и не является примером хорошей практики.

Однако если вы действительно встретите такое приложение, ваш собственный apphook для него, в свою очередь, должен будет отказаться от атрибута app_name.

Обратите внимание, что в отличие от apphooks без атрибутов app_name могут быть прикреплены только к одной странице за один раз; попытка применить их во второй раз приведет к ошибке. Может существовать только один экземпляр этих apphooks.

Подробнее о наличии нескольких экземпляров apphook смотрите в Прикрепление приложения несколько раз.

Возвращение URL-адресов apphook вручную

Вместо того, чтобы определять шаблоны URL в другом файле myapp/urls.py, можно также возвращать их вручную, например, если вам нужно переопределить предоставленный набор. Пример:

from django.urls import re_path
from myapp.views import SomeListView, SomeDetailView

class MyApphook(CMSApp):
    # ...
    def get_urls(self, page=None, language=None, **kwargs):
        return [
            re_path(r'^$', SomeListView.as_view()),
            re_path(r'^(?P<slug>[\w-]+)/?$', SomeDetailView.as_view()),
        ]

Однако гораздо удобнее хранить их в urls.py приложения, где они могут быть легко использованы повторно.

Загрузка новых и переконфигурированных apphooks

Некоторые изменения, связанные с apphook, требуют перезагрузки сервера для загрузки.

Когда бы вы ни были:

  • добавить или удалить apphook

  • изменить slug страницы, содержащей apphook, или slug страницы, у которой есть потомок с apphook

кэши URL должны быть перезагружены.

Если у вас установлен cms.middleware.utils.ApphookReloadMiddleware, что рекомендуется, сервер сделает это за вас, автоматически переинициализируя шаблоны URL.

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

Использование apphook

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

Примечание

apphook не будет ничего делать, пока страница, к которой он принадлежит, не будет опубликована. Обратите внимание, что это также означает, что все родительские страницы также должны быть опубликованы.

apphook прикрепляет все URL-адреса приложения apphooked к странице; корневой URL будет собственным URL-адресом страницы, а все URL-адреса более низкого уровня будут находиться на том же пути URL.

Итак, в приложении с urls.py для представлений index_view и archive_view:

urlpatterns = [
    re_path(r'^$', index_view),
    re_path(r'^archive/$', archive_view),
]

прикрепленной к странице, путь URL которой /hello/world/, представления будут открыты следующим образом:

  • index_view при /hello/world/

  • archive_view при /hello/world/archive/

Вложенные страницы страницы apphooked

Важно

Не добавляйте дочерние страницы к странице с apphook.

apphook «заглатывает» все URL ниже страницы, передавая их подключенному приложению. Если у вас есть дочерние страницы страницы apphooked, django CMS не сможет их надежно обслуживать.

Управление apphooks

Деинсталляция apphook с примененными экземплярами

Если вы удалите класс apphook из вашей системы (фактически деинсталлировав его), который все еще имеет экземпляры, применяемые к страницам, django CMS попытается справиться с этим настолько изящно, насколько это возможно:

  • На затронутых страницах сохраняется запись о примененном apphook; если класс apphook впоследствии будет восстановлен, он будет работать как прежде.

  • В списке страниц будут отображаться индикаторы apphook, где это необходимо.

  • В остальном страница будет вести себя как обычная страница django CMS, и отображать свои заполнители обычным образом.

  • Если вы сохраните Дополнительные настройки страницы, apphook будет удален.

Команды управления

Вы можете очистить неустановленные экземпляры apphook с помощью команды управления CMS uninstall apphooks. Например:

manage.py cms uninstall apphooks MyApphook MyOtherApphook

Вы можете получить список установленных apphooks с помощью команды cms list; в данном случае:

manage.py cms list apphooks

Более подробную информацию см. в Management commands reference.

Добавление меню в apphooks

Как правило, рекомендуется позволить пользователю контролировать, прикреплено ли меню к странице (См. Прикрепить меню подробнее об этих меню). Однако при необходимости можно сделать так, чтобы apphook делал это автоматически. Он будет вести себя так же, как если бы меню было прикреплено к странице с помощью его Дополнительных настроек).

Меню можно добавить в apphook с помощью метода get_menus(). На основе приведенного выше примера:

# [...]
from myapp.cms_menus import MyAppMenu

class MyApphook(CMSApp):
    # [...]
    def get_menus(self, page=None, language=None, **kwargs):
        return [MyAppMenu]

Изменено в версии 3.3: CMSApp.get_menus() заменяет CMSApp.menus. Атрибут menus устарел и был удален в версии 3.5.

Меню, возвращаемые в методе get_menus(), должны возвращать список узлов в своих методах get_nodes(). В Прикрепить меню есть больше информации о создании классов меню, которые генерируют узлы.

Вы можете вернуть несколько классов меню; все они будут прикреплены к одной странице:

def get_menus(self, page=None, language=None, **kwargs):
    return [MyAppMenu, CategoryMenu]

Управление разрешениями на apphooks

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

Чтобы отключить это поведение, установите permissions = False в вашем apphook:

class MyApphook(CMSApp):
    [...]
    permissions = False

Если вы все еще хотите, чтобы некоторые из ваших представлений использовали проверки разрешений CMS, вы можете включить их с помощью декоратора, cms.utils.decorators.cms_perms.

Вот простой пример:

from cms.utils.decorators import cms_perms

@cms_perms
def my_view(request, **kw):
    ...

Если вы делаете собственные проверки разрешений в своем приложении, то используйте свойство exclude_permissions в apphook:

class MyApphook(CMSApp):
    [...]
    permissions = True
    exclude_permissions = ["some_nested_app"]

где вы указываете название приложения, о котором идет речь

Автоматический перезапуск сервера при изменении apphook

Как упоминалось выше, всякий раз, когда вы:

  • добавить или удалить apphook

  • изменение slug страницы, содержащей apphook

  • изменение slug страницы с потомком с помощью apphook

CMS сервер будет перезагружать свои кэши URL. Для этого он прослушивает сигнал cms.signals.urls_need_reloading.

Предупреждение

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

Сигнал срабатывает после запроса - например, при сохранении настроек страницы. Если вы измените настройки apphook через API, сигнал не будет подан до следующего запроса.

Apphooks и тэги шаблонов

Важно понимать, что хотя apphooked приложение полностью берет на себя страницу CMS в этом месте, в зависимости от того, как шаблоны приложения расширяют другие шаблоны, тег шаблона django CMS {% placeholder %} может быть вызван - но не будет работать.

С другой стороны, теги {% static_placeholder %} не специфичны для страницы и будут функционировать нормально.

Вернуться на верх