2010-01-31 3 views
12

Есть ли способ расширить другие приложения ModelAdmin?Django - Расширение других приложений ModelAdmin?

У меня есть проект, который использует функциональные возможности, предлагаемые django.contrib.comments.

CommentsAdmin ModelAdmin класс имеет:
actions = ["flag_comments", "approve_comments", "remove_comments"]

Я хотел бы продлить CommentsAdmin ModelAdmin в моем проекте включить действие ban_user.

Я попытался создать свой собственный объект NewCommentsAdmin(CommentsAdmin) в своем файле admin.py и зарегистрировать его, но я получаю уведомление 'AlreadyRegistered at /admin/' 'The model Comment is already registered'.

class NewCommentAdmin(CommentAdmin): 
    actions = ['ban_user'] 

    def ban_user(self, request, queryset): 
     pass 

admin.site.register(Comment, NewCommentAdmin) 

Есть ли способ сделать это без изменения исходного кода django.contrib.comments?

ответ

3

Я думаю, у вас есть что-то вроде этого в верхней части файла:

from django.contrib.comments.admin import CommentAdmin 

Этот импорт выполняет регистрацию модели (в самом низу этого файла администратора) снова.

Одна мысль, что не выглядит очень красиво (я на самом деле не пробовал) может быть:

from django.contrib.comments.models import Comment 
from django.contrib import admin 
from django.contrib.admin.sites import NotRegistered 

# Try to unregister the Comment model 
# that was registered via the auto_discover method 
try: 
    admin.site.unregister(Comment) 
except NotRegistered: 
    pass 

# Now we can load the CommentAdmin (which reregisters the admin model) 
from django.contrib.comments.admin import CommentAdmin 

# We have to unregister again: 
try: 
    admin.site.unregister(Comment) 
except NotRegistered: 
    pass 

# Now your stuff... 

Я думаю, это можно было бы сделать лучше, но он должен работать. Чтобы этот подход работал, приложение, которое содержит этот файл, должно быть после приложения комментариев в INSTALLED_APPS.

Теперь вашему классу. Я думаю, что если вы напишете actions = ['ban_user'], вы фактически перезапишите все действия в родительском классе. Я думаю, что это самый простой способ, чтобы переопределить get_actions метод:

class NewCommentAdmin(CommentAdmin): 

    def get_actions(self, request): 
     actions = super(NewCommentAdmin, self).get_actions(request) 

     # Do some logic here based on request.user if you want 
     # to restrict the new action to certain users 
     actions.append('ban_user') 

     return actions 

    def ban_user(self, request, queryset): 
     pass 

admin.site.register(Comment, NewCommentAdmin) 

Надежда, что помогает (или по крайней мере дает представление) :)

+0

Ум, это намного сложнее, чем необходимо. Просто импортируйте CommentAdmin, подклассируйте его, отмените регистрацию один раз и зарегистрируйте свою версию. –

+0

@ Карл Мейер: Вы уверены? Я попытался получить виджет карты Geodjango, работающий в интерфейсе. Для этого мне нужно было импортировать собственный пользовательский AdminModel, определенный в файле 'admin.py'. Когда я импортирую этот класс, функция 'admin.site.register' была выполнена снова. Это моя точка зрения. Когда вы пытаетесь импортировать класс, он пытается снова зарегистрировать модель.Сработали ли вы с успехом? Если есть другое решение, я более чем доволен здесь. –

+0

Код уровня модуля выполняется только дважды, если модуль импортируется двумя разными путями. Как правило, этого не должно быть. Я не знаю, делает ли GeoDjango что-то напуганное, никогда не использовал его. См. Мой ответ для простой версии, что я работаю на производстве. –

9

Вот как я это делаю в одном проекте для модели пользователя. В admin.py для моего приложения:

from django.contrib import admin 
from django.contrib.auth.admin import UserAdmin 
from django.contrib.auth.models import User 

class MyUserAdmin(UserAdmin): 
    # ... 

admin.site.unregister(User) 
admin.site.register(User, MyUserAdmin) 
0

Посмотрите https://github.com/kux/django-admin-extend

предлагает несколько простых в использовании функций и декораторы, которые реализуют функциональность вы запрашиваете очень гибко. В документации достаточно хорошо объясняется, почему использование этого подхода лучше, чем прямое наследование.

У этого также есть поддержка для инъекций двунаправленных многих во многие поля.