Oct/08
25
Django-plus: para que serve? (parte 2)
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 ;)
Marinho Brandão