Administratorze Django, ukryj model

86

Na stronie głównej serwisu administracyjnego, gdzie pojawiają się zarejestrowane modele, chcę ukryć kilka modeli, które są zarejestrowane dla administratora Django.

Jeśli wyrejestruję je bezpośrednio, nie będę w stanie dodawać nowych rekordów, ponieważ znika symbol dodawania nowego znaku „+”.

Jak można to zrobić?

Hellnar
źródło

Odpowiedzi:

124

W oparciu o odpowiedź x0nix przeprowadziłem kilka eksperymentów. Wygląda na to, że zwrócenie pustego dyktu z get_model_permswyklucza model z pliku index.html, a jednocześnie umożliwia bezpośrednią edycję instancji.

class MyModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        """
        Return empty perms dict thus hiding the model from admin index.
        """
        return {}

admin.site.register(MyModel, MyModelAdmin)
shaunsephton
źródło
Zgoda. Tylko to jest problem, gdy nie chcę zmieniać kodu. Chodzi mi o to, że mam aplikację podstawową, którą chcę usunąć z zależności od innych aplikacji. Zachowuję te zależności w pochodnej aplikacji specyficznej dla projektu. Teraz chcę, aby interfejs administratora wyświetlał tylko aplikację pochodną, ​​a nie aplikację podstawową. Django wymaga, aby aplikacja podstawowa była wymieniona w ustawieniach / INSTALLED_APPS, aby aplikacja pochodna działała. Oczywiście aplikacja podstawowa nie powinna się wyświetlać, ale jednocześnie nie chcę, aby była niezmodyfikowana i wielokrotnego użytku. Zobacz [tutaj] ( Stack Exchange / questions / 13923968 /).
Sven
6
Krótsza droga:get_model_perms = lambda self, req: {}
Tigran Saluev
2
A jeśli chcę ukryć model przed określonym administratorem użytkownika?
Alireza Sanaee
1
Uważaj na to rozwiązanie - nawet jeśli link zniknie, użytkownik może przeskoczyć do samego obiektu w ten sposób: / admin / main / comment / 2333 / change /
goodgrief
32

Dla Django 1.8 i nowszych

Od Django 1.8 ModelAdminma nową metodę o nazwie, has_module_permission()która jest odpowiedzialna za wyświetlanie modelu w indeksie administratora.

Aby ukryć model przed indeksem administratora, po prostu utwórz tę metodę w swojej ModelAdminklasie i zwróć False. Przykład:

class MyModelAdmin(admin.ModelAdmin):
    ...
    def has_module_permission(self, request):
        return False
xyres
źródło
Niestety has_module_permissionwpływa na całą aplikację, a nie tylko na jeden model. Więc dodanie tego do modelu w aplikacji powoduje 403 zabronione na liście modeli aplikacji (/ admin / app_label /). Zobacz django / contrib / admin / sites.py .
Fabian
1
@Fabian Myślę, że to błąd. Zapytałem o to na kanale IRC Django i niektórzy ludzie zgadzają się, że takie zachowanie jest niepożądane.
xyres
@Fabian Zakładając, że strona indeksu administratora nadal prowadzi do / admin / , możliwe jest obejście tego błędu przez coś takiego return request.path!='/admin/'. Niestety, powoduje to ponowne włączenie tych modeli na liście modeli aplikacji.
ecp
Otworzyłem tutaj zgłoszenie dotyczące tego błędu. Zostało to naprawione tutaj . Miejmy nadzieję, że powinno znaleźć się w następnym wydaniu.
xyres
W Django 1.11 głębokie łącze nadal działa, ale podmiot nie jest wymieniony na głównym ekranie administratora
Csaba Toth
22

Mam ten sam problem, oto co wymyśliłem.

Podobnie jak w poprzednim rozwiązaniu - skopiuj index.html z django do swojego /admin/index.html i zmodyfikuj go w ten sposób:

{% for model in app.models %}
    {% if not model.perms.list_hide %}
    <tr>
    ...
    </tr>
    {% endif %}
{% endfor %}

I utwórz podklasę ModelAdmin:

class HiddenModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, *args, **kwargs):
        perms = admin.ModelAdmin.get_model_perms(self, *args, **kwargs)
        perms['list_hide'] = True
        return perms

Teraz żaden model zarejestrowany w podklasie HiddenModelAdmin nie pojawi się na liście administratorów, ale będzie dostępny szczegółowo za pośrednictwem symbolu „plus”:

class MyModelAdmin(HiddenModelAdmin):
    ...

admin.site.register(MyModel, MyModelAdmin)
x0nix
źródło
1

Brzydkie rozwiązanie: zastąp szablon indeksu administratora, tj. Skopiuj index.html z django do swojego /admin/index.html i dodaj coś takiego:

{% for for model in app.models %}
    {% ifnotequal model.name "NameOfModelToHide" %}
    ...
alex vasi
źródło
1

Jest to alternatywny sposób budowania na podstawie odpowiedzi x0nix i tylko wtedy, gdy z przyjemnością ukryjesz wiersze za pomocą jquery.

Skopiuj wklejanie z drugiej odpowiedzi część, której ponownie użyłem

class HiddenModelAdmin(admin.ModelAdmin):
def get_model_perms(self, *args, **kwargs):
    perms = admin.ModelAdmin.get_model_perms(self, *args, **kwargs)
    perms['list_hide'] = True
    return perms

class MyModelAdmin(HiddenModelAdmin):
...

admin.site.register(MyModel, MyModelAdmin)

Następnie zainstaluj django-jquery, a następnie dodaj następujący blok do swojego /admin/index.htmlszablonu:

{% extends "admin:admin/index.html" %}

{% block extrahead %}
    <script type="text/javascript" src="{{ STATIC_URL }}js/jquery.js"></script>
    {% if app_list %}
      <script type="text/javascript">
        $(function(){
          {% for app in app_list %}
            {% for model in app.models %}
                {% if model.perms.list_hide %}
                    $('div.app-{{ app.app_label }}').find('tr.model-{{ model.object_name|lower }}').hide();
                {% endif %}
            {% endfor %}
          {% endfor %}
        });
     </script>
   {% endif %}
{% endblock %}

Nie musisz kopiować, wklejać całego szablonu, po prostu rozszerz go i nadpisuj extraheadblok. Będziesz potrzebować szablonów django-apptemplates, aby powyższe działało.

Panos
źródło
0

Django 1.2 ma nowe instrukcje if, co oznacza, że ​​żądaną funkcję można uzyskać tylko przez nadpisanie admin / index.html

{% if model.name not in "Name of hidden model; Name of other hidden model" %}
    ...
{% endif %}

To złe rozwiązanie, ponieważ nie dba o wielojęzycznych administratorów. Możesz oczywiście dodać nazwy modeli we wszystkich obsługiwanych językach. To dobre rozwiązanie, ponieważ nie zastępuje więcej niż jednego aspektu podstawowych funkcji Django.

Ale zanim cokolwiek zmienię, myślę, że ludzie powinni o tym pomyśleć ...

Zasadniczo problem jest związany z posiadaniem modeli, których nie chce się używać na dłużej niż dodawanie opcji do listy rozwijanej od czasu do czasu. Można to skutecznie obejść, tworząc zestaw uprawnień dla „niezbyt zaawansowanych” użytkowników, którzy wpadają w panikę, gdy jest zbyt wiele modeli. W przypadku konieczności wprowadzenia zmian w poszczególnych modelach wystarczy zalogować się na „konto zaawansowane”.

benjaoming
źródło
0

Miałem wielu administratorów modelu do zarejestrowania i ukrycia, jeśli chcesz bardziej SUCHEGO rozwiązania, to zadziałało dla mnie (Django 1.10, Python 3.5)

# admin.py

def register_hidden_models(*model_names):
    for m in model_names:
        ma = type(
            str(m)+'Admin',
            (admin.ModelAdmin,),
            {
                'get_model_perms': lambda self, request: {}
            })
        admin.site.register(m, ma)

register_hidden_models(MyModel1, MyModel2, MyModel3)

Myślę, że możesz przekształcić go w klasę użytkową, jeśli chcesz ponownie użyć go w różnych aplikacjach.

murraybiscuit
źródło
0

Jak Django 1.8.18 , has_module_permission()wciąż ma problem. Tak więc w naszym przypadku użyliśmy również get_model_perms(). Podobnie, musimy ukryć model tylko dla określonego użytkownika, ale superuserpowinien on mieć dostęp do swojego wpisu indeksu.

class MyModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        if not request.user.is_superuser:
            return {}
        return super(MyModelAdmin, self).get_model_perms(request)

admin.site.register(MyModel, MyModelAdmin)
Ranel Padon
źródło