如何过滤 wagtail 管理中的页面列表,以便编辑者只能看到他们创建的页面?

How to filter page lists in the wagtail admin so editors only see pages they created?

我正在创建一个 wagtail 网站,用户可以在其中注册、登录到 wagtail 管理员并编写要发布的文章页面。 wagtail admin 中是否有拦截和过滤数据的钩子或可能的方法,以便用户只能看到他们自己创建的文章页面?

到目前为止,我已经使用 django-allauth 设置了用户注册,并且用户能够成功登录。一旦注册,user_signed_up 接收者就会触发,用户将被分配到 'Author' 角色。在管理员中,作者只能添加文章。 Articles 是一个带有文章索引页和文章页(基本上是博客和博客索引页)的应用程序。一旦他们登录,他们唯一看到的就是左侧的“页面”选项卡,单击该选项卡会将他们带到 'Articles' 列表。他们可以在这里添加 'Article' 页面并查看他们目前创建的文章。

这也是我的问题所在。在文章列表页面,用户可以看到站点上所有用户创建的所有文章。他们只能编辑自己的,这很好,但最终会有数百篇来自其他用户的文章。有没有办法在 'Articles' 数据显示之前拦截它并由当前用户过滤?

拦截此数据的结果将使登录到 wagtail 管理员的每个用户只知道他们创建的文章页面。

非常感谢,这是我第一次使用 Wagtail,到目前为止我很喜欢它。

我发现了这个问题的两种不同的解决方案。

  1. 实施 ModelAdmin 以创建模型的自定义页面列表视图。这使您可以创建一个全新的管理菜单项和相应的列表视图。此方法涉及更多,但提供更多控制。
  2. 按组对文件管理器结果实施 construct_explorer_page_queryset 管理挂钩。此方法实施起来快速且容易,并允许您使用 Wagtails 现有的页面浏览器。

我将介绍我是如何处理上述每种方法的。两者都有效,这是决定我是否更喜欢使用页面浏览器中内置的 Wagtails 的问题。

方法一:ModelAdmin

ModelAdmin.get_queryset() 的使用和其他有用的方法在 Wagtail 文档中找到 here

根据 Wagtail 文档中的 this page,我将 ModelAdmin 添加到 INSTALLED_APPS:

# base.py settings

INSTALLED_APPS = [
    ...
    'wagtail.contrib.modeladmin',
]

然后我在我的 'article' 应用程序中创建了一个名为 wagtail_hooks.py 的文件。在该文件中,我添加了代码以在管理员中创建我的文章列表页面:

# wagtail_hooks.py

from wagtail.contrib.modeladmin.options import (ModelAdmin, modeladmin_register)
from .models import Article


class ArticleAdmin(ModelAdmin):
    model = Article
    menu_label = 'Articles'
    menu_icon = 'doc-full-inverse'
    menu_order = 000
    add_to_settings_menu = False
    exclude_from_explorer = False
    list_display = ('title', 'owner')
    search_fields = ('title', 'owner')

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        #only show articles from the current user
        return qs.filter(owner=request.user)


modeladmin_register(ArticleAdmin)

这里的关键是实现 ModelAdmin.get_queryset() 让我过滤文章所有者。

您可能还想删除页面浏览器菜单项,因为它有点多余。我还建议也实施下面的方法 2。即使您删除了页面浏览器菜单项,用户也可能通过直接在浏览器中输入 URL 来到达那里。如果他们这样做,实施方法 2 将确保看不到其他用户创作的内容。

方法二:construct_explorer_page_queryset @hooks

Wagtail 文档中的 hook 信息 - construct_explorer_page_queryset 还引用了这篇 Google 网上论坛文章 - https://groups.google.com/forum/#!topic/wagtail/10tcq8PB8io

在我上面创建的同一个 wagtail_hooks.py 文件中,我添加了以下代码:

@hooks.register('construct_explorer_page_queryset')
def show_authors_only_their_articles(parent_page, pages, request):
    user_group = request.user.groups.filter(name='Author').exists()
    if user_group:
        pages = pages.filter(owner=request.user)

    return pages

第二种方法就是这些。

@Pahikua 请注意,方法 2 只是将页面从列表中隐藏起来,并不能防止页面被编辑和删除。在您的情况下,这意味着 Author1 可以像 pages/id/edit/ 这样打开 url,其中 id 是 Author2 拥有的页面的 ID 并对其进行编辑。

要避免这种情况,您必须添加 before_edit_page 和 before_delete_page 挂钩。像这样:

@hooks.register('before_edit_page')
def before_edit_page(request, page):
    user_group = request.user.groups.filter(name='Author').exists()
    if user_group and page.owner != request.user:
        raise PermissionDenied

感谢@Pahikua 和@Igor Margitich。我能够将他们的答案组合成一个漂亮的排列,这正是我想要的。

  1. 按照@Pahikua 在他的方法 1 中的建议,为文章(或您希望作者能够使用的任何其他模型)创建一个管理菜单项。这将为作者提供快速访问其内容的快捷方式(甚至可以从此处添加内容)。

  2. 我没有删除 Page Explorer 管理菜单项,因为我真的希望我的作者能够浏览其他作者的页面,以便找到正确的位置来添加他们的页面。
    否则, 仅从新创建的文章菜单项(在步骤 1 中)将页面添加到正确位置非常麻烦。

  3. 按照@Igor Margitich 的建议添加这些“之前”挂钩。我也使用了 before_create_page 挂钩,因为我希望我的作者只能添加一种类型的页面。
from wagtail.core import hooks
from django.core.exceptions import PermissionDenied
from django.views.defaults import permission_denied
from .models import Article

@hooks.register('before_edit_page')
def before_edit_page(request, page):
    # user_group = request.user.groups.filter(name='Author').exists() # I did not use user_group
    if not (request.user.is_superuser or page.owner == request.user):
        return permission_denied(request, PermissionDenied("You do not have permission to edit this page."))
    
@hooks.register('before_delete_page')
def before_delete_page(request, page):
    if not (request.user.is_superuser or page.owner == request.user):
        return permission_denied(request,PermissionDenied("You do not have permission to delete this page."))
    
@hooks.register('before_create_page')
def before_create_page(request, parent_page, page_class):
    if not (request.user.is_superuser or page_class == Article):
        return permission_denied(request, PermissionDenied("You do not have permission to add this page."))