Django 管理中同一模型的多个 ModelAdmins/视图

发布于 2024-08-20 20:43:58 字数 1076 浏览 5 评论 0原文

如何为同一模型创建多个 ModelAdmin,每个模型的定制方式不同并链接到不同的 URL?

假设我有一个名为 Posts 的 Django 模型。默认情况下,该模型的管理视图将列出所有 Post 对象。

我知道我可以通过设置 list_display 等变量或覆盖 ModelAdmin 中的 queryset 方法,以各种方式自定义页面上显示的对象列表,如下所示:

class MyPostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date')

    def queryset(self, request):
        request_user = request.user
        return Post.objects.filter(author=request_user)

admin.site.register(MyPostAdmin, Post)

默认情况下,可以通过 URL <代码>/admin/myapp/post。但是,我希望拥有同一模型的多个视图/模型管理员。例如 /admin/myapp/post 将列出所有帖子对象,而 /admin/myapp/myposts 将列出属于该用户的所有帖子,而 /admin/ myapp/draftpost 可能会列出所有尚未发布的帖子。 (这些只是示例,我的实际用例更复杂)

您不能为同一模型注册多个 ModelAdmin(这会导致 AlreadyRegistered 异常)。理想情况下,我希望实现此目标,无需将所有内容放入单个 ModelAdmin 类中并编写自己的“url”函数以根据 URL 返回不同的查询集。

我查看了 Django 源代码,发现像 ModelAdmin.changelist_view 这样的函数可以以某种方式包含在我的 urls.py 中,但我不确定它到底是如何工作的。

更新:我找到了一种实现我想要的功能的方法(见下文),但我仍然想听听其他实现此目的的方法。

How can I create more than one ModelAdmin for the same model, each customised differently and linked to different URLs?

Let's say I have a Django model called Posts. By default, the admin view of this model will list all Post objects.

I know I can customise the list of objects displayed on the page in various ways by setting variables like list_display or overriding the queryset method in my ModelAdmin like so:

class MyPostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date')

    def queryset(self, request):
        request_user = request.user
        return Post.objects.filter(author=request_user)

admin.site.register(MyPostAdmin, Post)

By default, this would be accessible at the URL /admin/myapp/post. However I would like to have multiple views/ModelAdmins of the same model. e.g /admin/myapp/post would list all post objects, and /admin/myapp/myposts would list all posts belonging to the user, and /admin/myapp/draftpost might list all posts that have not yet been published. (these are just examples, my actual use-case is more complex)

You cannot register more than one ModelAdmin for the same model (this results in an AlreadyRegistered exception). Ideally I'd like to achieve this without putting everything into a single ModelAdmin class and writing my own 'urls' function to return a different queryset depending on the URL.

I've had a look at the Django source and I see functions like ModelAdmin.changelist_view that could be somehow included in my urls.py, but I'm not sure exactly how that would work.

Update: I've found one way of doing what I want (see below), but I'd still like to hear other ways of doing this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

提赋 2024-08-27 20:43:58

我找到了一种方法来实现我想要的,即使用代理模型来绕过每个模型只能注册一次的事实。

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pubdate','user')

class MyPost(Post):
    class Meta:
        proxy = True

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)


admin.site.register(Post, PostAdmin)
admin.site.register(MyPost, MyPostAdmin)

然后,可以在 /admin/myapp/post 访问默认的 PostAdmin,并且用户拥有的帖子列表将位于 /admin/myapp/myposts< /代码>。

在查看 http://code.djangoproject.com/wiki/DynamicModels 后,我来了使用以下函数实用程序函数来执行相同的操作:

def create_modeladmin(modeladmin, model, name = None):
    class  Meta:
        proxy = True
        app_label = model._meta.app_label

    attrs = {'__module__': '', 'Meta': Meta}

    newmodel = type(name, (model,), attrs)

    admin.site.register(newmodel, modeladmin)
    return modeladmin

可以按如下方式使用:

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)

create_modeladmin(MyPostAdmin, name='my-posts', model=Post)

I've found one way to achieve what I want, by using proxy models to get around the fact that each model may be registered only once.

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pubdate','user')

class MyPost(Post):
    class Meta:
        proxy = True

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)


admin.site.register(Post, PostAdmin)
admin.site.register(MyPost, MyPostAdmin)

Then the default PostAdmin would be accessible at /admin/myapp/post and the list of posts owned by the user would be at /admin/myapp/myposts.

After looking at http://code.djangoproject.com/wiki/DynamicModels, I've come up with the following function utility function to do the same thing:

def create_modeladmin(modeladmin, model, name = None):
    class  Meta:
        proxy = True
        app_label = model._meta.app_label

    attrs = {'__module__': '', 'Meta': Meta}

    newmodel = type(name, (model,), attrs)

    admin.site.register(newmodel, modeladmin)
    return modeladmin

This can be used as follows:

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)

create_modeladmin(MyPostAdmin, name='my-posts', model=Post)
雨后彩虹 2024-08-27 20:43:58

保罗·斯通的回答绝对很棒!只是补充一下,对于 Django 1.4.5,我需要从 admin.ModelAdmin 继承我的自定义类

class MyPostAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(id=1)

Paul Stone answer is absolutely great! Just to add, for Django 1.4.5 I needed to inherit my custom class from admin.ModelAdmin

class MyPostAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(id=1)
南笙 2024-08-27 20:43:58

根据正确答案,我对 AdminSite 类进行了猴子修补,并添加了 register_via_proxy 方法以使任务变得更容易。

import re
from django.contrib import admin

def _register_proxy(self, model, admin_class):
    proxy_model = type(
        admin_class.__name__, (model,), {
            "__module__": re.sub(
                r'(^.*?)(\.[^\.]+)

使用方法如下:

site = admin.sites.AdminSite()
site.register_via_proxy(models.ModelType, AdminClass)

, r'\1.proxy', model.__module__ ), "Meta": type("Meta", tuple(), { "proxy": True, "app_label": model._meta.app_label }) } ) return self.register(proxy_model, admin_class) admin.sites.AdminSite.register_via_proxy = _register_proxy

使用方法如下:

Based on the correct answers, I monkeypatch the AdminSite class and add the method register_via_proxy to make the task easier.

import re
from django.contrib import admin

def _register_proxy(self, model, admin_class):
    proxy_model = type(
        admin_class.__name__, (model,), {
            "__module__": re.sub(
                r'(^.*?)(\.[^\.]+)

And to use is like:

site = admin.sites.AdminSite()
site.register_via_proxy(models.ModelType, AdminClass)

, r'\1.proxy', model.__module__ ), "Meta": type("Meta", tuple(), { "proxy": True, "app_label": model._meta.app_label }) } ) return self.register(proxy_model, admin_class) admin.sites.AdminSite.register_via_proxy = _register_proxy

And to use is like:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文