DetailView - Django class-based generic views - II

Aquela view que exibe os detalhes de um objeto pelo slug ou pk pode ser bem fácil de se fazer com generic views.

Introdução

Quando precisamos listar os detalhes de um objeto que, geralmente, está em um banco de dados, nós encontramos e selecionamos ele pela sua chave primária (pk) ou mesmo pelo (slug). Vamos ver como fazer isto com a classe DetailView do Django.

Para uma melhor interação do usuário para/com a aplicação, geralmente, não esperamos que ele saiba de cabeça a url para acessar os detalhes de um objeto, por isso criamos sempre uma listagem de objetos contendo os links para acessar mais informações sobre os mesmos. Esta listagem de objetos é abordada no primeiro artigo dessa série de artigos sobre class-based generic views.

De fato, será bom se você ler, ao menos, o trecho introdutório do artigo ListView - Django class-based generic views - I para entender o exemplo que estou usando para fazer as views desta série de artigos.

DetailView - listando as informações de um objeto

Vamos listar as listas de reprodução que estão cadastradas minha base de dados. Para isto só precisamos importar, dentro de views.py, o meu model e a classe DetailView. Como no exemplo abaixo:

views.py

from django.views.generic import DetailView
from app_exemplo.models importListaDeReproducao

class DetalhesListasDeReproducao(DetailView):
    model = ListaDeReproducao

Bem fácil! No template, por padrão, faríamos assim:

listadereproducao_detail.html

<h1>{{ listadereproducao.titulo }}</h1>
<p>{{ listadereproducao.descricao }}</p>
<p>
    Criada: <strong>{{ listadereproducao.criado }}</strong> |
    Atualizada: <strong>{{ listadereproducao.modificado }}</strong>
</p>

<!--
NOTE:
Abaixo eu listo todos os arquivos de áudio pertencentes à minha "Lista de reprodução".
Para entender melhor a composição do meu model ListaDeReprodução, visite:
app_exemplo/models.py
-->

<ul>
{% for audio in listadereproducao.audios.all %}
    <li>
        <p><a href="{{ MEDIA_URL }}{{ audio.audio }}">{{ audio.titulo }}</a></p>
        <p>{{ audio.descricao }}</p>
        <p>Última atualização: {{ audio.modificado|timesince }}</p>
    </li>
{% endfor %}
</ul>

Personalizando a DetailView

Para fazer mais com DetailView podemos personalizar outros atributos que têm valores padrão mas que podemos alterá-los e manipulá-los. Vamos ver os principais:

template_name

A personalização deste atributo é feita da mesma forma que no ListView, veja mais na view ListasDeReproducao. O que muda é que se você não definir, automaticamente ela vai buscar o seguinte template: listadereproducao_detail.html que é a soma do nome do Model + o tipo de view: Model: ListaDeReproducao e View: DetailView.

Para informar a localização do template com o nome personalizado basta fazer como no exemplo abaixo:

# ...
class DetalhesListasDeReproducao(DetailView):
    # ...
    template_name = 'app_exemplo/lista_de_reproducao_detalhes.html'

queryset

Como no ListView aqui você pode escolher entre fornecer o model e/ou o queryset.

Mas manipular queryset no DetailView seria para casos bem específicos, pois filtragem e outras coisas que podem ser feitas com o queryset são geralmente feitas já na hora de listar, no caso, em uma ListView e no DetailView o objeto selecionado já é o definitivo e queremos somente extrair informações dele. Para fazer maiores personalizações no objeto de contexto gerado pela DetailView é necessário manipular os objetos de contexto com o método get_context_data.

# ...
class DetalhesListasDeReproducao(DetailView):
    # ...
    queryset = ListaDeReproducao.objects.all()

context_object_name

Se você não der um nome para o objeto de contexto para manipular nos templates o nome dele será o nome do model, neste caso listadereproducao, em lower case mesmo. Ou poderá ser acessado, também, como object.

Se você visualizar as variáveis de contexto que estão sendo passadas para seu template verá algo assim:

{
     'listadereproducao': <ListaDeReproducao: Armas disparando>,
     'object': <ListaDeReproducao: Armas disparando>
}

Você pode personalizá-lo como no exemplo abaixo:

# ...
class DetalhesListasDeReproducao(DetailView):
    # ...
    context_object_name = 'lista_de_reproducao'

NOTE: Sobre Objetos de contexto

O objeto de contexto na DetailView é diferente da ListView, pois no conteúdo extraído do Model não temos uma lista e sim um objeto, já que a intenção é listar os detalhes de um objeto específico.

Não quer dizer que você não possa definir o método get_context_data e personalizar os objetos de contexto:

# ...
from models import OutroModel
class DetalhesListasDeReproducao(DetailView):
    # ...
    def get_context_data(self, **kwargs):
        context = super(DetalhesListasDeReproducao, self).get_context_data(**kwargs)
        # Aqui você fará inclusão, alteração ou exclusão de contextos como desejar
        # por exemplo, agora estou adicionando mais um objeto de contexto
        context['listas_de_outras_coisas'] = OutroModel.objects.all()
        return context

Conclusão

Então é isto, quaisquer dúvidas, críticas e sugestões façam nos comentários e/ou issues no repositório do projeto no github. Que a propósito você pode acompanhar o repositório "django-class-based-generic-views" e pode visualizar o exemplo que abordei aqui em projeto / app_exemplo / views / list_and_detail.py.

Até o próximo artigo!

blog comments powered by Disqus