Posted by José Lopes.
The Django administration has a couple of widgets that can be used in an user's form.
This is mentioned on the Django's documentation ( Media and Django Admin) but no practical example is given. Searching the web we find that a lot of people have tried to use them without success, specially the AdminDateWidget that provides a nice popup calendar for choosing the date.
This post show how one can use this widget, and explains why there have been so many missing attemps.
The information here presented is also valid for the AdminTimeWidget. Other widgets may be subject of future posts.
Lets start by the cause of the unsuccess in making the widget work, that at the same time is the solution.
If we check the admin page source we find the following line on the header:
<script type="text/javascript" src="../../../jsi18n/"></script>
This line executes the jsi18n script that, in a simple way to say it, calls a javascript code responsible for the substitution of specific divs (on the case of the AdminDateWidget is the div declared on the input as class="vDateField") by nice visual outputs like the button for the popup calendar. This code changes depending if our project uses or not internationalization.
The problem is that nothing happens even when we are including this line in our forms. This is due to fact that this script needs the admin authentication to work. More frustrating is that we get no error message neither any authentication request.
The solution is to force the running of the script content in our forms.
Following Django's philosophie (the famous DRY) we can create a file in our project media, to be more accurate at media/js/, with for instance the name adminwidgets.js. Inside this file we'll write the output of http://127.0.0.1:8000/admin/jsi18n/ that will be:
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())});
}
}
If your project has no internationalization.
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())});
}
}
If your project has internationalization. Despite the difference I would suggest to use the second so that you may include the internationalization in the future without more problems.
Saying this, in order to have a popup calendar working on a form one just have to follow the next two points:
1. Create the Form
Lets assume that we have a form from a model. The model has a field (mydatefield) of the date type. The form code should be something like:
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
Explaining the code:
(1) importing our model.
(2) importing the AdminDateWidget widget.
(3) we overwrite the mydatefield model definitions to be a date
field with the AdminDateWidget widget.
2. Create the form template
On the form template, that we can call myformtemplate.html, we must place the following lines on the 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 }}
Explaining the code:
(1) points to a copy of the file with the same name, originally at
django/contrib/admin/media/css,
that defines the calendar layout (with a copy we can always change at will);
(2) admin javascript;
(3) our javascript file that we created to solve the jsi18n question;
(4) includes the AdminDateWidget javascripts pre-defined, more precicely
the calendar.js and the DateTimeShortcuts.js
We're done and the calendar is working!
Until now I had found nothing documenting this so I hope it may be useful.
Parabens pelo post. Procurei e nao encontrei nada parecido.
Sendo que infelizmente, nao funcionou comigo. Sabe o que posso fazer?
ou me enviar o seu codigo de exemplo.