Отключить ссылку на объект редактирования в администраторе django (только для отображения списка)?

StackOverflow https://stackoverflow.com/questions/1618728

Вопрос

В администраторе Django я хочу отключить ссылки, предоставленные на странице "выберите элемент для изменения", позволяют пользователям никуда не ходить для редактирования элемента.(Я собираюсь ограничить то, что пользователи могут делать с этим списком, набором выпадающих действий - никакого фактического редактирования полей).

Я вижу, что у Django есть возможность выберите, в каких полях отображается ссылка, однако, я не вижу, как я могу иметь Нет из них.

class HitAdmin(admin.ModelAdmin):
    list_display = ('user','ip','user_agent','hitcount')
    search_fields = ('ip','user_agent')
    date_hierarchy = 'created'
    list_display_links = [] # doesn't work, goes to default

Есть идеи, как получить мой список объектов без каких-либо ссылок для редактирования?

Это было полезно?

Решение

Я хотел, чтобы средство просмотра журнала было только списком.

Я понял, что это работает так:

class LogEntryAdmin(ModelAdmin):
    actions = None
    list_display = (
        'action_time', 'user',
        'content_type', 'object_repr', 
        'change_message')

    search_fields = ['=user__username', ]
    fieldsets = [
        (None, {'fields':()}), 
        ]

    def __init__(self, *args, **kwargs):
        super(LogEntryAdmin, self).__init__(*args, **kwargs)
        self.list_display_links = (None, )

Это своего рода смесь между обоими ответами.

Если вы просто выполните self.list_display_links = () , он покажет ссылку. В любом случае, потому что код template-tag (templatetags / admin_list.py) снова проверяется на посмотреть, если список пуст.

Другие советы

Для правильного выполнения этого требуется два шага:

  • Скройте ссылку на редактирование, чтобы никто по ошибке не наткнулся на страницу сведений (изменить вид).
  • Измените вид изменения, чтобы перенаправить обратно в вид списка.

Вторая часть очень важна:если вы этого не сделаете, люди по-прежнему смогут получить доступ к представлению изменений, напрямую введя URL-адрес (который, предположительно, вам не нужен).Это тесно связано с тем, что OWASP называет "Небезопасная Прямая ссылка на объект".

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

Скрытие ссылки на редактирование

Django 1.7 делает это действительно простым:вы просто устанавливаете list_display_links Для None.

class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2
    list_display_links = None

Django 1.6 (и, предположительно, более ранние версии) не делают это таким простым.Довольно много ответов на этот вопрос предполагают переопределение __init__ для того, чтобы установить list_display_links после того, как объект был создан, но это затрудняет его повторное использование (мы можем переопределить конструктор только один раз).

Я думаю, что лучшим вариантом является переопределение Django get_list_display_links способ заключается в следующем:

def get_list_display_links(self, request, list_display):
    """
    Return a sequence containing the fields to be displayed as links
    on the changelist. The list_display parameter is the list of fields
    returned by get_list_display().

    We override Django's default implementation to specify no links unless
    these are explicitly set.
    """
    if self.list_display_links or not list_display:
        return self.list_display_links
    else:
        return (None,)

Это делает наш миксер простым в использовании:он скрывает ссылку редактирования по умолчанию, но позволяет нам добавить ее обратно, если требуется для конкретного представления администратора.

Перенаправление на просмотр списка

Мы можем изменить поведение страницы сведений (изменить вид), переопределив change_view способ.Вот дополнение к методике, предложенной Крисом Праттом, которое автоматически находит нужную страницу:

enable_change_view = False

def change_view(self, request, object_id, form_url='', extra_context=None):
    """
    The 'change' admin view for this model.

    We override this to redirect back to the changelist unless the view is
    specifically enabled by the "enable_change_view" property.
    """
    if self.enable_change_view:
        return super(ReportMixin, self).change_view(
            request,
            object_id,
            form_url,
            extra_context
        )
    else:
        from django.core.urlresolvers import reverse
        from django.http import HttpResponseRedirect

        opts = self.model._meta
        url = reverse('admin:{app}_{model}_changelist'.format(
            app=opts.app_label,
            model=opts.model_name,
        ))
        return HttpResponseRedirect(url)

Опять же, это можно настроить - переключая enable_change_view Для True вы можете снова включить страницу сведений.

Удаление кнопки "Добавить ПРЕДМЕТ" Кнопка

Наконец, вы можете переопределить следующие методы, чтобы запретить пользователям добавлять или удалять новые элементы.

def has_add_permission(self, request):
    return False

def has_delete_permission(self, request, obj=None):
    return False

Эти изменения приведут к:

  • отключите функцию "Добавить предмет" кнопка
  • запрещайте людям напрямую добавлять элементы, добавляя /add перейти по URL-адресу
  • предотвращение массового удаления

Наконец, вы можете удалить "Удалить выбранное Товары" действие путем изменения actions параметр.

Собирая все это воедино

Вот готовая смесь:

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2

    actions = None

    enable_change_view = False

    def get_list_display_links(self, request, list_display):
        """
        Return a sequence containing the fields to be displayed as links
        on the changelist. The list_display parameter is the list of fields
        returned by get_list_display().

        We override Django's default implementation to specify no links unless
        these are explicitly set.
        """
        if self.list_display_links or not list_display:
            return self.list_display_links
        else:
            return (None,)

    def change_view(self, request, object_id, form_url='', extra_context=None):
        """
        The 'change' admin view for this model.

        We override this to redirect back to the changelist unless the view is
        specifically enabled by the "enable_change_view" property.
        """
        if self.enable_change_view:
            return super(ReportMixin, self).change_view(
                request,
                object_id,
                form_url,
                extra_context
            )
        else:
            opts = self.model._meta
            url = reverse('admin:{app}_{model}_changelist'.format(
                app=opts.app_label,
                model=opts.model_name,
            ))
            return HttpResponseRedirect(url)

    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

Как пользователь omat, упомянутый в комментарии выше, любая попытка просто удалить ссылки не мешает пользователям по-прежнему обращаться к странице изменений вручную. Однако это тоже достаточно легко исправить:

class MyModelAdmin(admin.ModelAdmin)
    # Other stuff here
    def change_view(self, request, obj=None):
        from django.core.urlresolvers import reverse
        from django.http import HttpResponseRedirect
        return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

В Django 1.7 и более поздних версиях вы можете сделать

class HitAdmin(admin.ModelAdmin):
    list_display_links = None

В вашей модели админ установлен:

list_display_links = (None,)

Это должно сделать это. (Работает в 1.1.1 в любом случае.)

Ссылка на документы: list_display_links

Нет поддерживаемого способа сделать это.

Глядя на код, кажется, что он автоматически устанавливает ModelAdmin.list_display_links на первый элемент, если вы ничего не устанавливаете. Поэтому самым простым способом может быть переопределение метода __ init __ в вашем подклассе ModelAdmin для сброса этого атрибута при инициализации:

class HitAdmin(admin.ModelAdmin):
    list_display = ('user','ip','user_agent','hitcount')
    search_fields = ('ip','user_agent')
    date_hierarchy = 'created'

    def __init__(self, *args, **kwargs):
        super(HitAdmin, self).__init__(*args, **kwargs)
        self.list_display_links = []

Похоже, это работает после очень краткого теста. Я не могу гарантировать, что это не сломает ничего в другом месте или что оно не будет сломано будущими изменениями в Django.

Изменить после комментария :

Нет необходимости исправлять источник, это будет работать:

    def __init__(self, *args, **kwargs):
        if self.list_display_links:
            unset_list_display = True
        else:
            unset_list_display = False
        super(HitAdmin, self).__init__(*args, **kwargs)
        if unset_list_display:
            self.list_display_links = []

Но я очень сомневаюсь, что любой патч будет принят в Django, поскольку это нарушает то, что код явно делает в данный момент.

Только для заметок вы можете изменить changelist_view:

class SomeAdmin(admin.ModelAdmin):
    def changelist_view(self, request, extra_context=None):
        self.list_display_links = (None, )
        return super(SomeAdmin, self).changelist_view(request, extra_context=None)

Это прекрасно работает для меня.

Вы также можете быть смехотворно по поводу этого (если вы не хотите возиться с переопределением init ) и укажите значение для первого элемента, которое в основном выглядит следующим образом:

</a>My non-linked value<a>

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

Вот пример кода о том, как это работает:

class HitAdmin(admin.ModelAdmin):
    list_display = ('user_no_link','ip','user_agent','hitcount')

    def user_no_link(self, obj):
        return u'</a>%s<a>' % obj
    user_no_link.allow_tags = True
    user_no_link.short_description = "user"

Примечание: вы также можете улучшить читабельность вывода (поскольку вы не хотите, чтобы это была ссылка), возвращая return u '% s'% obj.get_full_name () , который может быть довольно аккуратным в зависимости от вашего варианта использования.

с django 1.6.2 вы можете сделать это так:

class MyAdmin(admin.ModelAdmin):

    def get_list_display_links(self, request, list_display):
        return []

он будет скрывать все автоматически сгенерированные ссылки.

просто напишите list_display_links = None в вашем администраторе

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top