Django UtilidadesMarinho Brandão

Oct/08 25

Django-plus: para que serve? (parte 2)

django
Publicado há 2 months, 1 week por Marinho Brandao

Template Filters de comparação

Continuando a explanação sobre os recursos disponíveis no django-plus [1], eu gostaria somente de esclarecer um pouco mais sobre as template filters que disponibilizei no artigo anterior [2].

Vamos tomar a template filter is_equal como melhor exemplo.

O sistema de templates do Django disponibiliza apenas um meio para se fazer comparativo de igualdade, assim:
{% ifequal user.username 'marinho' %}
    exibe ou faz alguma coisa
{% endifequal %}

Notou a limitação? Não? Imagine que você precise colocar ali um simples AND, ou um OR. Não é possível ou no máximo é doloroso. Mas com a template tag {% if %} é possível, portanto, será nesse momento que você fará uso da template filter is_equal, assim:

{% load djangoplus_tags %}

{% if user.username|is_equal:'marinho' and user.is_staff %}
    exibe ou faz alguma coisa
{% endif %}

Compreendeu? Agora siga a mesma linha de raciocínio para as template filters is_not_equal (diferente), is_lt (menor que), is_lte (menor ou igual), is_gt (maior que), is_gte (maior ou igual) e in_list (na lista).

Agora, com as coisas esclarecidas, vamos adiante.

Model Info

Hoje vamos falar especificamente do pacote de funcionalidades model_info. Para que ele serve?

Bom, quando você quer criar um admin para uma classe de modelo, como você faz? Assim:

class AdminPessoa(ModelAdmin):
    fields = ('nome','idade',)

admin.site.register(Pessoa, AdminPessoa)

Simples né? Sim, muito. E para formulários de inclusão/alteração? Assim:

class FormPessoa(ModelForm):
    class Meta:
        model = Pessoa

Sim, isso é suficiente para seu formulário funcionar bem para a classe de model. Simples assim.

Agora, e quando você precisa listar os registros de uma queryset ou exibir as informações de um deles?

Bom, aí é aquela coisa: você vai carregar o objeto ou a lista de objetos e vai tratar campo por campo no template. Quando for necessário mais de uma vez, você vai criar um template e incluí-lo nos demais, para evitar repetição de código. Para quem se acostumou com as mágicas acima, esse processo é doloroso ou no mínimo entediante.

Então, para isso servem as classes e template tags do Model Info do django-plus.

Vamos a um exemplo de exibição de dados de um objeto de uma classe Pessoa:

views.py

from django.shortcuts import get_object_or_404, render_to_response
from models import Pessoa

def detalhes_da_pessoa(request, pessoa_id):
    pessoa = get_object_or_404(Pessoa, id=pessoa_id)
    return render_to_response('detalhes_da_pessoa.html', locals())

info.py

from djangoplus.model_info import ModelInfo
from models import Pessoa

class InfoPessoa(ModelInfo):
    class Meta:
        model = Pessoa

detalhes_da_pessoa.html (template)

{% load djangoplus_tags %}

<table class="info">
    {% model_info_for_object 'minha_aplicacao.info.InfoPessoa' pessoa %}
</table>

Absurdamente simples, não? Neste caso, não importa se sua classe Pessoa possua 2 ou 50 campos, eles serão todos (à exceção de ManyToManyField) listados comportadamente na tabela informada e funcionará bem.

Vamos fazer uma listagem? Ok, vamos lá:

views.py (acrescente as linhas ao fim do arquivo)

def lista_de_pessoas(request):
    pessoas = Pessoa.objects.all()
    return render_to_response('lista_de_pessoas.html', locals())

info.py (acrescente as linhas ao fim do arquivo)

from djangoplus.model_info import ModelList

class ListPessoa(ModelList):
    class Meta:
        model = Pessoa

lista_de_pessoas.html (template)

{% load djangoplus_tags %}

<table class="list">
    {% model_info_for_list 'minha_aplicacao.info.ListPessoa' pessoas %}
</table>

Da mesma forma, será exibida uma lista dos objetos da queryset pessoas, e se a classe Pessoa possuir o método get_absolute_url declarado, serão exibidos também ícones para edição e exclusão, seguindo as convenções comuns "{{ objeto.get_absolute_url }}edit/" e "{{ objeto.get_absolute_url }}delete/", respectivamente.

Mas é só isso? Para funcionar o básico, sim, mas aquela subclasse "Meta" permite diversas outras formas de customização.

Vamos falar primeiramente da classe ModelInfo:

  • fields - lista dos campos a serem exibidos;
  • exclude - lista dos campos a não serem exibidos (não é muito inteligente usar o fields e o exclude ao mesmo tempo);
  • show_if_none - informe True ou False para mostrar campos com valor None ou não;
  • show_if_empty - informe True ou False para mostrar campos com valor vazio ou não;
  • auto_urlize - informe True ou False para transformar URLs em links;
  • auto_linebreaks - informe True ou False para mostrar quebras de linha em campos do tipo TextField;
  • list_display_links - lista dos campos que serão exibidos como link para a página do objeto (raramente usada);
  • fieldsets - lista de fieldsets. Segue o mesmo padrão do fieldsets do Admin;
  • row_template (default: '<tr><th>%s</th><td>%s</td></tr>') - permite que você informe o formato para exibir cada campo e seu referido valor;
  • fieldset_title_template (default: '<h3>%s</h3>') - permite que você informe o formato para exibir o título da fieldset;
  • show_fieldset_title - informe True ou False para exibir os títulos de fieldsets ou não;

Bacana não? Agora vamos para a classe ModelList:

  • fields - lista dos campos a serem exibidos;
  • exclude - lista dos campos a não serem exibidos (não é muito inteligente usar o fields e o exclude ao mesmo tempo;
  • show_if_none - informe True ou False para mostrar campos com valor None ou não;
  • show_if_empty - informe True ou False para mostrar campos com valor vazio ou não;
  • auto_urlize - informe True ou False para transformar URLs em links;
  • auto_linebreaks - informe True ou False para mostrar quebras de linha em campos do tipo TextField;
  • list_display_links - lista dos campos que serão exibidos como link para a página do objeto (raramente usada);
  • td_template (default: '<td>%s</td>') - formato para exibir cada célula da tabela;
  • th_template (default: '<th>%s</th>') - formato para exibir cada célula do cabeçalho da tabela;
  • tr_template (default: '<tr>%s</tr>') - formato para exibir cada linha da tabela;
  • thead_template (default: '<thead><tr>%s</tr></thead>') - formato para exibir o cabeçalho da tabela;
  • tbody_template (default: '<tbody>%s</tbody>') - formato para exibir o corpo de dados da tabela;
  • icon_edit_template (default: '<a href="%(edit_url)s" title="Edit this"><img src="%(media_url)simg/admin/icon_changelink.gif" alt="Edit"/></a>') - formato para exibir o ícone de edição (informe vazio para não ser exibido);
  • icon_delete_template (default: '<a href="%(delete_url)s" title="Delete this"><img src="%(media_url)simg/admin/icon_deletelink.gif" alt="Edit"/></a>') - formato para exibir o ícone de exclusão (informe vazio para não ser exibido);
  • group_template (default: '<tr><td colspan="%(cols)s" class="group"><h3>%(display)s</h3></td></tr>') - formato para agrupamentos;
  • groups - lista dos campos pelos quais os registros serão agrupados; 

Ufa! Mais poderoso e flexível do que pensava, não? Mas ainda tem mais.

Tanto na classe ModelInfo quanto na ModelList, é possível informar métodos seguindo as sintaxes e regras abaixo:

  • get_CAMPO_display(self, f_name) - retorna um título customizado para o campo em questão;
  • get_CAMPO_value(self, f_name, instance) - retorna um valor customizado e/ou tratado para o campo em questão. Isso lhe permite declarar campos calculados ou que são parte de uma instância diferente da instância que está sendo carregada. O campo em questão deve ser informado no atributo "fields" da subclasse META ou ao menos ser parte da classe e não estar no atributo "exclude";
  • render_buttons_cell(self, instance, edit_url=None, delete_url=None) - caso sobrecarregue este campo, é possível mudar o padrão das URLs de edição e exclusão do objeto;

Por fim, a classe ModelInfo permite que também ser declarada diretamente na view e ser chamada para cada campo solitariamente, assim:

views.py

from django.shortcuts import get_object_or_404, render_to_response
from models import Pessoa
from info import InfoPessoa

def detalhes_da_pessoa(request, pessoa_id):
    pessoa = get_object_or_404(Pessoa, id=pessoa_id)
    info_pessoa = InfoPessoa(pessoa)
    return render_to_response('detalhes_da_pessoa.html', locals())

detalhes_da_pessoa.html (template)

{% load djangoplus_tags %}
{{ info_pessoa.nome }}

Gostou? E algo semelhante pode ser feito com a classe ModelList, que é iterável:

views.py (acrescente as linhas ao fim do arquivo)

from info import ListPessoa

def lista_de_pessoas(request):
    pessoas = Pessoa.objects.all()
    lista_pessoas = ListPessoa(pessoas)

    return render_to_response('lista_de_pessoas.html', locals())

lista_de_pessoas.html (template)

{% load djangoplus_tags %}

<table class="list">
    {% for pessoa in lista_pessoas %}
    <tr><td>{{ pessoa }}</td></tr>
    {% endfor %}
</table>

Bom, é isso aí, espero que ajude. Eu ganho um bom temp usando esses recursos, acho que podem ser úteis para você também ;)

Links relacionados

  1. http://code.google.com/p/django-plus/
  2. http://marinhobrandao.com/blog/p/django-plus-para-que-serve/

Links sociais


Comentários


Escreva o seu


.net adoradores ajax android apple banco de dados blogosfera brasil django emprego família gadgets google inovação java linux lua microsoft musica opensocial opinião publicidade python rails religiao screencast seguranca software-livre tdd web windows yadsel

Artigos recentes