【问题标题】:How to filter page lists in the wagtail admin so editors only see pages they created?如何在 wagtail 管理员中过滤页面列表,以便编辑者只能看到他们创建的页面?
【发布时间】:2019-04-25 07:31:30
【问题描述】:

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

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

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

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

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

【问题讨论】:

标签: wagtail


【解决方案1】:

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

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

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

方法一:模型管理

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

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

# base.py settings

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

然后我在我的“文章”应用中创建了一个名为 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 文档中的钩子信息 - 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

这就是第二种方法。

【讨论】:

  • 在您的get_queryset() 中,您不能按qs.filter(owner=request.user) 过滤页面吗?
  • 感谢@KalobTaulien 的建议。这不仅有效,而且需要更少的代码并消除了向数据库添加不必要的字段。我已经更新了上面的代码以反映您的建议。
【解决方案2】:

@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

【讨论】:

    【解决方案3】:

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

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

    2. 我没有删除页面资源管理器管理菜单项,因为我确实希望我的作者能够浏览其他作者的页面,以便找到添加页面的正确位置。
      否则,将页面添加到仅从新创建的文章菜单项(在步骤 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."))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多