Este é um post de José Lopes.
O admin do Django tem uma série de widgets que podem ser utilizados em qualquer form do utilizador.
Na documentação do Django é feita referência a isso ( Media and Django Admin) mas nenhum exemplo prático é dado. Em buscas pela internet verificamos que muita gente tentou utilizar esse widgets sem sucesso, especialmente o AdminDateWidget que possibilita ter um agradável calendário popup para escolher a data.
Este post mostra como utilizar este widget, explicando o porquê de tantas tentativas falhadas.
A informação apresentada também é válida para o widget AdminTimeWidget. Outros widgets poderão ser objecto de outros posts caso se justifique.
Vamos começar pela causa de não se conseguir por a funcionar o widget, que ao mesmo tempo é a solução.
Se analisarmos a página da administração encontramos no header a seguinte linha:
<script type="text/javascript" src="../../../jsi18n/"></script>
Esta linha executa o script jsi18n que, dito de uma forma resumida, chama um código em javascript responsável pela substituição de certos divs (no caso do AdminDateWidget é o div declarado no input como class="vDateField") por um display visual como o botão para o calendário popup. Este código varia consuante se esteja a utilizar ou não a internacionalização.
O problema é que mesmo incluindo esta linha nas nossas forms nada se passa. O problema é devido a este script necessitar de autenticação do administrador. Mais ingrato se torna quando não temos nenhuma mensagem de erro nem nenhum pedido de autenticação.
A solução passa então por forçarmos a correr o conteúdo do script nas nossas forms.
Por uma questão de filosofia do Django (o famoso DRY) vamos criar um ficheiro no media do nosso projecto, mais concretamente em media/js/, com o nome de adminwidgets.js. Dentro deste ficheiro vamos colocar o output de http://127.0.0.1:8000/admin/jsi18n/ que será:
function gettext(msgid) { return msgid; } function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; } function gettext_noop(msgid) { return msgid; } function interpolate(fmt, obj, named) { if (named) { return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); } else { return fmt.replace(/%s/g, function(match){return String(obj.shift())}); } }
Para o caso de um projecto sem internacionalização.
var catalog = new Array(); function pluralidx(count) { return (count == 1) ? 0 : 1; } function gettext(msgid) { var value = catalog[msgid]; if (typeof(value) == 'undefined') { return msgid; } else { return (typeof(value) == 'string') ? value : value[0]; } } function ngettext(singular, plural, count) { value = catalog[singular]; if (typeof(value) == 'undefined') { return (count == 1) ? singular : plural; } else { return value[pluralidx(count)]; } } function gettext_noop(msgid) { return msgid; } function interpolate(fmt, obj, named) { if (named) { return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); } else { return fmt.replace(/%s/g, function(match){return String(obj.shift())}); } }
Para o caso de um projecto com internacionalização. De qualquer forma eu sugeria a utilização do segundo caso, pois no futuro poderemos querer fazer a internacionalização e nesse caso já temos o projecto preparado.
Posto isto, para ter o calendário popup a funcionar numa form basta seguir os dois pontos seguintes:
1. Criar a Form
Vamos assumir que temos uma form baseada num modelo, modelo esse que tem um campo (mydatefield) do tipo data. O código da form terá de ser algo do tipo:
from django import forms (1) from my_project.myuserapp.models import MyUserModel (2) from django.contrib.admin.widgets import AdminDateWidget class MyUserForm(forms.ModelForm): (3) mydatefield = forms.DateField(widget=AdminDateWidget) class Meta: model = MyUserModel
Explicando o código:
(1) importamos o nosso modelo.
(2) importamos o widget AdminDateWidget.
(3) definimos o campo mydatefield do nosso modelo
como um campo de data com o widget AdminDateWidget.
2. Criar o template da form
No template da form, que podemos chamar myformtemplate.html, temos de colocar as seguintes linhas no header:
(1) <link rel="stylesheet" type="text/css" href="/media/css/widgets.css"/></link> (2) <script type="text/javascript" src="/admin_media/js/core.js"></script> (3) <script type="text/javascript" src="/media/js/adminwidgets.js"></script> (4) {{ form.media }}
Explicando o código:
(1) aponta para uma cópia do ficheiro com o mesmo nome em
django/contrib/admin/media/css
e que formata o calendário (copiando o ficheiro sempre o podemos alterar ao nosso gosto);
(2) javascript da administração;
(3) inclui o ficheiro de javascript que criámos para resolver a questão do jsi18n;
(4) inclui os javascripts pré-definidos do AdminDateWidget, mais concretamente
o calendar.js e o DateTimeShortcuts.js
Não é necessário mais nada e já temos o calendário a funcionar!
Até agora não encontrei nada disto documentado pelo que espero que vos seja útil.