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

В администраторе 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 

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

    9 Solutions collect form web for “Отключить ссылку для редактирования объекта в администраторе django (только для отображения списка)?”

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

    Я начал работать так:

     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 класс 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 после того, как объект был создан, но это затрудняет повторное использование (мы можем только переопределить конструктор один раз).

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

     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,) 

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

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

    Мы можем изменить поведение страницы подробностей (вид изменения), переопределив метод 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 вы можете снова переключить страницу сведений.

    Удаление кнопки «Добавить ITEM »

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

     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 в любом случае.)

    Это не поддерживается.

    Глядя на код, кажется, что он автоматически устанавливает ModelAdmin.list_display_links в первый элемент, если вы его не устанавливаете. Таким образом, самый простой способ – переопределить метод __init__ в подклассе ModelAdmin чтобы 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() которое может быть немного опрятным в зависимости от вашего 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 [] 

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

    Python - лучший язык программирования в мире.