覆盖特定模型的 Django 管理 URL?

发布于 2024-11-02 03:45:28 字数 781 浏览 3 评论 0原文

首先是一些背景知识:

我有一个包含各种 event_typeEvent 模型。我想将这些事件类型之一“电影”分解到它自己的管理中。我已经具备了基本功能:一个继承自 Event 的代理模型,名为 Film,该代理模型的自定义管理器将其过滤为仅“电影”事件类型,它有自己的 ModelAdmin。

问题出在相反的情况下。我现在需要从主 Event 管理员中过滤掉电影。我不想更改 Event 模型或其默认管理器,因为影响太广泛了。因此,我尝试创建另一个代理模型 EventAdminProxy,其唯一目的是在管理中提供经过筛选的事件列表。然后,我使用现有的 ModelAdmin 注册该模型,而不是 Event

这显然是有效的,但它有一个不幸的副作用,即更改管理中的 URL。更改列表不再位于“/admin/event/event/”,而是现在位于“/admin/event/eventadminproxy/”。

我想做的是保留此设置,但也保留旧的 URL。我尝试过重载 ModelAdmin 的 get_urls 方法,但据我所知,您无法控制那里的完整 URL,只能控制“/app_label/model_class/”部分之后的内容。

我考虑过在主 urls.py 中覆盖它,但无法找出可以接受的视图来结合。实际视图仅在实例化的 ModelAdmin 对象上可用,而在类本身上不可用。

关于如何覆盖管理员中使用的 URL 有什么想法吗?

First a little background:

I have an Event model that has various event_types. I want to break one of those event types, 'Film', into it's own admin. I have the basic functionality in place: a proxy model inheriting from Event, named Film, a custom manager for that proxy model that filters it to only 'film' event types, and it's own ModelAdmin.

The problem is with the reverse. I now need to filter out films from the main Event admin. I don't want to alter the Event model or its default manager, because the impact would be too widespread. So, I tried creating another proxy model, EventAdminProxy, with the sole purpose of providing a filtered list of events in the admin. I then register this model, instead of Event, with the existing ModelAdmin.

This obviously works, but it has the unfortunate side-effect of altering the URLs in the admin. Instead of the changelist being at "/admin/event/event/", it's now at "/admin/event/eventadminproxy/".

What I'm trying to do is keep this setup, but also keep the old URL. I've tried overloading the ModelAdmin's get_urls method, but from what I can tell, you can't control the full URL there, only what comes after the "/app_label/model_class/" part.

I thought about overriding it in the main urls.py, but can't figure out an acceptable view to tie into. The actual views are only available on the instantiated ModelAdmin object, not the class itself.

Any ideas of how override the URL being used in the admin?

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

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

发布评论

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

评论(3

音盲 2024-11-09 03:45:28

查看 Django 源代码,管理 URL 构建在两个位置:ModelAdmin 实例和 AdminSite 实例。

您想要更改的部分是在 AdminSite 实例 (django.contrib.admin.sites.AdminSite) 中构建的,您可以对其进行子类化并重写 get_urls 方法。如果您查看该方法的后半部分,您会看到以下内容:

 # 添加每个模型的视图。
    对于模型,self._registry.iteritems() 中的 model_admin:
        urlpatterns += 模式('',
            url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name),
                包括(model_admin.urls))
        )

在那里添加模型的 ._meta.module_name ,它只是模型的小写名称(django.db.models.options.Options.contribute_to_class)。

一个简单的方法是重写站点的 get_urls 方法,并为代理模型添加一个字典或特殊情况,以便它使用不同的 url 而不是 model._meta.module_name,类似的事情:

类 MyAdminSite(AdminSite):

module_name_dict = {
    EventAdminProxy:“myfunkymodulename”
}

def get_urls(自身):
    base_patterns = super(MyAdminSite, self).get_urls()
    my_patterns = 模式('',)

    对于模型,self._registry.iteritems() 中的 model_admin:
        如果模型在 self.module_name_dict 中:
            module_name = self.module_name_dict[型号]
            my_patterns += 模式('',
                url(r'^%s/%s/' % (model._meta.app_label, module_name),
                    包括(model_admin.urls))
            )

    返回 my_patterns + 基本模式

Looking at the Django source, the admin URLs are built in two places, in the ModelAdmin instances, and in the AdminSite instances.

The part you want to change is built in the AdminSite instance (django.contrib.admin.sites.AdminSite), you can subclass that and override the get_urls method. If you look at the second half of the method you'll see this:

    # Add in each model's views.
    for model, model_admin in self._registry.iteritems():
        urlpatterns += patterns('',
            url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name),
                include(model_admin.urls))
        )

There it is adding the model's ._meta.module_name which is just the model's name lowercased (django.db.models.options.Options.contribute_to_class).

An easy way out is to override the Site's get_urls method and add a dict or special case for the Proxy model so it uses a different url instead of model._meta.module_name, something along the lines:

class MyAdminSite(AdminSite):

module_name_dict = {
    EventAdminProxy: 'myfunkymodulename'
}

def get_urls(self):
    base_patterns = super(MyAdminSite, self).get_urls()
    my_patterns = patterns('',)

    for model, model_admin in self._registry.iteritems():
        if model in self.module_name_dict:
            module_name = self.module_name_dict[model]
            my_patterns += patterns('',
                url(r'^%s/%s/' % (model._meta.app_label, module_name),
                    include(model_admin.urls))
            )

    return my_patterns + base_patterns
十年九夏 2024-11-09 03:45:28

您可以覆盖 queryset-method您的 EventModelAdmin 并过滤查询集,以便排除电影事件。

与此类似的东西:

class EventAdmin(admin.ModelAdmin):

    def queryset(self, request):
        qs = super(EventAdmin, self).queryset(request)
        return qs.exclude(event_type='film')

You could override the queryset-method of your EventModelAdmin and filter the queryset so that Film-Events get excluded.

Something similar to this:

class EventAdmin(admin.ModelAdmin):

    def queryset(self, request):
        qs = super(EventAdmin, self).queryset(request)
        return qs.exclude(event_type='film')
要走就滚别墨迹 2024-11-09 03:45:28

您还可以子类化 ChangeList 并重写 url_for_result() 方法来自定义更改 url,(从 另一个答案),例如:

from django.contrib.admin.views.main import ChangeList

class FooChangeList(ChangeList):
    def url_for_result(self, obj):
        return '/foos/foo/{obj.pk}/'

class FooAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return FooChangeList

问题的改编示例:

from django.contrib.admin.views.main import ChangeList
from django.urls import reverse

class FilmAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        class FilmChangeList(ChangeList):
            def url_for_result(self, obj):
                return reverse('admin:events_event_change', args=(obj.pk, ))
        return FilmChangeList

You could also subclass ChangeList and override the url_for_result() method to customise change urls, (learned from another answer), e.g.:

from django.contrib.admin.views.main import ChangeList

class FooChangeList(ChangeList):
    def url_for_result(self, obj):
        return '/foos/foo/{obj.pk}/'

class FooAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return FooChangeList

Adapted example for the question:

from django.contrib.admin.views.main import ChangeList
from django.urls import reverse

class FilmAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        class FilmChangeList(ChangeList):
            def url_for_result(self, obj):
                return reverse('admin:events_event_change', args=(obj.pk, ))
        return FilmChangeList
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文