自定义Django AdminModel视图

2 投票
3 回答
2209 浏览
提问于 2025-04-16 21:52

在我的Django应用中,我为所有未注册的用户创建了Guest用户账户(它们的邮箱都是'guest@mysite.com')。同时,我还为这些Guest账户创建了一些演示对象。这些对象和注册用户的对象在同一个表里(也就是同一个模型)。而且,我有不止一种类型(模型)的这些对象,比如:

class Object1(models.Model):
    user = ForeignKey(...)
    ...

class Object2(models.Model):
    user = ForeignKey(...)
    ...

我想要实现的目标是,当我在django管理后台查看这些对象时,能够过滤掉所有与Guest账户相关的对象。

目前,我是通过子类化django.contrib.admin.views.main.ChangeList,并重写get_query_set方法来排除这些对象的,同时在运行时重新定义了django的ModelAdmin类的get_changelist方法:

class FilteredChangeList(ChangeList):
    def get_query_set(self):
        qs = super(FilteredChangeList, self).get_query_set()
        if is_related_to(self.model, Profile):
            qs = qs.exclude(user__email='guest@mysite.com')
        return qs

def my_getchangelist(self, request, **kwargs):
    return FilteredChangeList

ModelAdmin.get_changelist = my_getchangelist

我觉得在运行时重新定义django的方法可能不是个好做法,那么有没有什么正确的解决方案呢?

3 个回答

1

你可以创建一个新的类,继承自 ModelAdmin,并且重写 get_changelist 这个方法,而不是在运行时重新定义它。

class FilteredModelAdmin(ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return FilteredChangeList

然后,用 FilteredModelAdmin 来注册你的模型,而不是用 ModelAdmin

admin.site.register(Object1, FilteredModelAdmin)
admin.site.register(Object2, FilteredModelAdmin)

如果你需要为你的模型自定义其他设置,可以继承 FilteredModelAdmin,而不是 ModelAdmin

class Object1ModelAdmin(FilteredModelAdmin)
    # other customizations here

admin.site.register(Object1, Object1ModelAdmin)
2

你还可以使用代理模型。比如,你可以有一个模型是用来表示“真实”用户的,另一个模型则用来表示“访客”用户的。

5

看起来你可能做了很多不必要的工作。你可以自己创建一个 ModelAdmin 类,并重写它的 queryset 方法,这样就不需要自己构建一个 ChangeList 类了。

class MyFilteredAdmin(admin.ModelAdmin):
    def queryset(self, request):
        qs = super(MyFilteredAdmin, self).queryset(request)
        if is_related_to(self.model, Profile):
            qs = qs.exclude(user__email='guest@mysite.com')
        return qs

然后你可以直接用这个新的管理类来注册你的模型,比如 admin.site.register(Model, MyFilteredAdmin),或者创建一些子类,让它们继承自 MyFilteredAdmin,而不是直接继承自 Django 的 ModelAdmin

撰写回答