Pergunta

administração do Em Django, quero desativar os links fornecidos na página "selecione o item a mudança" para que os usuários não podem ir a qualquer lugar para editar o item. (Estou indo para limitar o que os usuários podem fazer com esta lista a um conjunto de drop down ações - sem edição real de campos).

Eu vejo que o Django tem a capacidade de escolha quais campos exibir o link , no entanto, eu não posso ver como eu posso ter nenhum deles.

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

Todas as idéias como obter minha lista de objeto sem quaisquer links para editar?

Foi útil?

Solução

Eu queria um visualizador de Log como uma lista única.

Eu tenho que trabalhar assim:

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

É uma espécie de mistura entre ambas as respostas.

Se você acabou de fazer self.list_display_links = () ele irá mostrar o link, de qualquer maneira porque o código template-tag (templatetags / admin_list.py) verifica novamente para ver se a lista está vazia.

Outras dicas

Fazendo isso corretamente exige duas etapas:

  • Ocultar o link de edição, para que ninguém tropeça na página de detalhes (vista mudança) por engano.
  • Modificar o ponto de vista a mudança para redirecionar de volta para a exibição de lista.

A segunda parte é importante: se você não fizer isso, então as pessoas ainda será capaz de acessar a exibição mudança, inserindo um URL diretamente (que presumivelmente você não quer). Isto está intimamente relacionado com o que OWASP prazo de um "Inseguro direto Object Reference" .

Como parte dessa resposta que eu vou construir uma classe ReadOnlyMixin que pode ser usado para fornecer toda a funcionalidade mostrado.

Escondendo o Edit Link

Django 1.7 faz isso realmente fácil:. Você acabou de definir list_display_links para None

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

Django 1.6 (e, presumivelmente, mais cedo) não fazem isso tão simples. Um monte de respostas para essa pergunta sugeriram substituir __init__, a fim de set list_display_links após o objeto foi construído, mas isso torna mais difícil a reutilização (só podemos substituir o construtor uma vez).

Eu acho que a melhor opção é substituir o método get_list_display_links do Django a seguinte:

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

Isso faz com que nossa mixin fácil de usar:. Esconde no link editar por padrão, mas nos permite adicioná-lo de volta se necessário para uma visão de administração especial

redirecionam para a visualização de lista

Nós podemos mudar o comportamento da página de detalhes (vista da mudança), substituindo o método change_view. Aqui está uma extensão da técnica sugerida por Chris Pratt, que encontra automaticamente a página direita:

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)

Novamente, isto é customizável - alternando enable_change_view para True você pode alternar a parte de trás detalhes página on

.

Retirar o "Adicionar ITEM " Botão

Finalmente, você pode querer substituir os seguintes métodos, a fim de evitar que as pessoas adicionar ou excluir novos itens.

def has_add_permission(self, request):
    return False

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

Estas mudanças irão:

  • desativar a opção "Adicionar item " botão
  • impedir que pessoas adicionando os itens diretamente anexando /add ao URL
  • evitar a granel de exclusão

Finalmente, você pode remover o "Excluir selecionados itens " ação, modificando o parâmetro actions.

Juntando tudo

Aqui está o mixin concluída:

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

Como usuário, omat, mencionado em um comentário anterior, qualquer tentativa de simplesmente remover os links não impedir que os usuários ainda acessar a página de alteração manualmente. No entanto, isso também é bastante fácil de remédio:

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

Em Django 1.7 e posterior, você pode fazer

class HitAdmin(admin.ModelAdmin):
    list_display_links = None

No seu conjunto modelo admin:

list_display_links = (None,)

Isso deve fazê-lo. (Obras em 1.1.1 de qualquer maneira.)

Link para docs: list_display_links

Não há uma forma suportada para fazer isso.

Olhando para o código, parece que define automaticamente ModelAdmin.list_display_links para o primeiro elemento se você não configurá-lo para qualquer coisa. Assim, a maneira mais fácil pode ser para substituir o método __init__ na sua subclasse ModelAdmin para desconfigurar esse atributo na inicialização:

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 = []

Esta parece trabalho, após um teste muito superficial. Eu não pode garantir que ele não vai quebrar nada em outro lugar, ou que ele não vai ser quebrado por alterações futuras Django, no entanto.

Editar após comentário :

Não há necessidade de corrigir a fonte, isso iria funcionar:

    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 = []

Mas eu duvido qualquer remendo seria aceito em Django, uma vez que este breaks algo que o código faz explicitamente no momento.

Apenas para as notas, você pode modificar 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)

Esta multa funciona para mim.

Você também poderia ser ridiculamente hacky sobre isso (se você não queria confusão com substituindo init) e fornecer um valor para o primeiro elemento que, basicamente parece isto:

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

Eu sei, eu sei, não muito bonito, mas talvez menos ansiedade sobre quebrar alguma coisa em outro lugar uma vez que todos nós estamos fazendo está mudando marcação.

Aqui está um código de exemplo sobre como isso funciona:

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"

Nota lateral: Você também pode melhorar a legibilidade da saída (desde que você não quer que ele seja um link), retornando return u'%s' % obj.get_full_name() que pode ser kinda limpo dependendo do seu caso de uso

.

com django 1.6.2 você pode fazer assim:

class MyAdmin(admin.ModelAdmin):

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

ele vai esconder toda auto ligações gerado.

apenas list_display_links = None escrever em seu admin

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top