Modelo inteiro como somente leitura

Existe uma maneira de fazer um modelo somente leitura no django admin? mas eu quero dizer todo o modelo. Então, sem adição, sem exclusão, sem alteração, basta ver os objetos e os campos, tudo como somente leitura?

13
É um trabalho em andamento que parece: github.com/django/django/pull/5297
adicionado o autor Bosco, fonte

5 Respostas

ModelAdmin fornece o gancho get_readonly_fields() - o seguinte não foi testado, minha idéia é determinar todos os campos da maneira que o ModelAdmin faz, sem executar uma recursão com os próprios campos readonly:

from django.contrib.admin.util import flatten_fieldsets

class ReadOnlyAdmin(ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if self.declared_fieldsets:
            fields = flatten_fieldsets(self.declared_fieldsets)
        else:
            form = self.get_formset(request, obj).form
            fields = form.base_fields.keys()
        return fields

então subclasse/mixin neste admin onde ele deve ser um admin de somente leitura.

Para adicionar/excluir e para fazer com que seus botões desapareçam, provavelmente você também desejará adicionar

    def has_add_permission(self, request):
        # Nobody is allowed to add
        return False
    def has_delete_permission(self, request, obj=None):
        # Nobody is allowed to delete
        return False

P.S .: No ModelAdmin, se has_change_permission (lookup ou seu override) retorna False, você não chega à visão de mudança de um objeto - e o link para ele nem será mostrado. Na verdade, seria legal se assim fosse, e o padrão get_readonly_fields() verificou a permissão change e definiu todos os campos como readonly nesse caso, como acima. Dessa forma, os não-trocadores poderiam, pelo menos, procurar os dados ... dado que a estrutura administrativa atual assume view = edit, como jathanism aponta, isso provavelmente exigiria a introdução de uma permissão "view" em cima de add/change/delete ...

EDIT: sobre a definição de todos os campos readonly, também não testado, mas parecendo promissor:

readonly_fields = MyModel._meta.get_all_field_names()

EDIT: aqui está outro

if self.declared_fieldsets:
    return flatten_fieldsets(self.declared_fieldsets)
else:
    return list(set(
        [field.name for field in self.opts.local_fields] +
        [field.name for field in self.opts.local_many_to_many]
    ))
11
adicionado
PS: Agora criei uma solicitação de recurso para esse efeito code.djangoproject.com/ticket/17295
adicionado o autor Danny W. Adair, fonte
Nota: o método get_formset é definido apenas para InlineModelAdmin
adicionado o autor Vajk Hermecz, fonte
Oi, obrigado por esta compilação de opções. Pode ser educado, embora também forneça os links para as respostas das quais você tirou as peças, pois eu vejo que elas não são todas suas. Outra vantagem seria que os leitores também pudessem ver os comentários feitos por outras pessoas sobre cada uma das sugestões.
adicionado o autor steps, fonte
Não funciona no Django 1.11 - AttributeError: o objeto 'ReadOnlyAdmin' não tem atributo 'declared_fieldsets'
adicionado o autor turbotux, fonte

Como as "permissões de visualização" não serão incluídas no Django 1.11 , infelizmente , aqui está uma solução que torna o seu ModelAdmin somente leitura fazendo as alterações do modelo de salvamento e adicionando entradas de registro de histórico de modelo a no-op .

def false(*args, **kwargs):
    """A simple no-op function to make our changes below readable."""
    return False

class MyModelReadOnlyAdmin(admin.ModelAdmin):
    list_display = [
        # list your admin listview entries here (as usual) 
    ]
    readonly_fields = [
        # list your read-only fields here (as usual)
    ]

    actions = None
    has_add_permission = false
    has_delete_permission = false
    log_change = false
    message_user = false
    save_model = false

( OBSERVAÇÃO: Não confunda o auxiliar sem código false com o código interno False . Se você não simpatizar com a função auxiliar fora a classe move-a para a classe, chame-a de no_op ou outra coisa, ou substitua os atributos afetados pelo def s usual. Menos DRY, mas se você não se importa. ..)

Isso vai:

  1. remova a caixa suspensa de ações (com "excluir") na exibição de lista </​​li>
  2. não permitir adicionar novas entradas de modelo
  3. não permitir a exclusão de entradas de modelo existentes
  4. evite criar entradas de registro no histórico do modelo
  5. evite exibir mensagens "foi alterado com sucesso" depois de salvar
  6. evite salvar alterações de alterações no banco de dados

Não vai:

  • remova ou substitua os dois botões "Salvar e continuar editando" e "SALVAR" (o que seria ótimo para melhorar a experiência do usuário)

Note que get_all_field_names (como mencionado na resposta aceita) foi removido no Django 1.10 . Testado com o Django 1.10.5.

3
adicionado

Você pode personalizar suas classes ModelAdmin com o readonly_fields . Consulte esta resposta para saber mais.

2
adicionado
Existe, mas não é fácil. Você é capaz de criar permissões personalizadas no Django, mas quando se trata do site admin não é trivial. O Django assume que, se as pessoas tiverem permissão para visualizar o conteúdo na interface de administração, elas também poderão editá-lo. Você pode tentar a sugestão de esta pergunta se estiver se sentindo em negrito. IMO é apenas mais fácil definir explicitamente todos os campos somente leitura e seguir em frente.
adicionado o autor jathanism, fonte
mas existe uma maneira de fazer o modelo inteiro como read_only, sem ter que adicionar todos os seus atributos à lista readonly_fields?
adicionado o autor juliomalegria, fonte

De acordo com o meu teste no Django 1.8, nós não podemos usar o seguinte como notado na resposta # 3, mas ele funciona em Django 1.4 :

##     self.get_formset(request, obj)      ##
answer 3 needs fix. Generally, alternative codes for this issue about below section 
##          form = self.get_formset(request, obj).form    ##
##          fields = form.base_fields.keys()              ##

Pode ser algo como:

#~ (A) or
[f.name for f in self.model._meta.fields]

#~ (B) or
MyModel._meta.get_all_field_names()

#~ (C) 
list(set([field.name for field in self.opts.local_fields] +
                        [field.name for field in self.opts.local_many_to_many]         
  ))
1
adicionado

Eu tive um cenário semelhante onde:

  1. O usuário deve poder criar os objetos do modelo
  2. O usuário deve poder visualizar a listagem de objetos de modelo
  3. O usuário NÃO DEVE editar um objeto depois de criado

1. Substituindo a exibição de alteração

Como é possível substituir o change_view() em um ModelAdmin, podemos explorá-lo para impedir a edição de instâncias do modelo depois que elas forem criadas. Aqui está um exemplo que usei:

def change_view(self, request, object_id, form_url='', extra_context=None):
    messages.error(request, 'Sorry, but editing is NOT ALLOWED')
    return redirect(request.META['HTTP_REFERER'])

2. Condicionalmente Alterar Permissões de Edição

Eu também percebi que os documentos interpretam o resultado de ModelAdmin.has_change_permission() de maneiras diferentes:

Deve retornar True se for permitido editar obj, Falso caso contrário. E se   obj é None, deve retornar True ou False para indicar se a edição   de objetos desse tipo é permitido em geral (por exemplo, False será   interpretado como significando que o usuário atual não tem permissão para editar   qualquer objeto deste tipo).

Significando que eu poderia verificar se obj é None , nesse caso eu retorno True , caso contrário eu retorno False , e Isso permite que os usuários visualizem a lista de mudanças, mas não possam editar nem visualizar o change_form após a instância do modelo ser salva.

def has_change_permission(self, request, obj = None, **kwargs):
    if obj is None:
        return True
    else:
        return False

Embora eu esteja pensando que isso também pode substituir quaisquer permissões de MODEL_can_change permitindo que olhos indesejados vejam a lista de mudanças?

0
adicionado