Pour produire un formulaire Web attrayant et simple à utiliser, il faut un peu plus que du simple HTML - il faut aussi des feuilles de style CSS, et si vous voulez utiliser les widgets “Web 2.0” élaborés, vous devrez aussi incorporer du JavaScript dans chaque page. Le CSS et le JavaScript requis pour chacune de vos pages dépendra des widgets qui vous y placerez.
C’est là qu’interviennent les définitions média de Django. Django vous permet d’associer différents fichiers média aux formulaires et widgets qui en ont besoin.
Par exemple, si vous utilisez un calendrier pour mettre en forme les DateFields, vous pouvez définir un widget Calendar personnalisé. Ce widget peut alors être associé au CSS et au JavaScript nécessaire pour mettre en forme le calendrier. Lorsque le widget Calendrier est utilisé dans un formulaire, Django est capable d’identifier les fichiers CSS et JavaScript nécessaires, et fournit la liste de noms de fichiers adéquats pour une inclusion facile dans votre page Web.
Media et Django Admin
L’application Django Admin définit un nombre de widgets personnalisés pour des calendriers, des sélections filtrées, etc. Ces widgets définissent des besoins de médias, et Django Admin utilise ces widgets personnalisés à la place de ceux livrés par défaut par Django. Les templates Admin n’incluront que les fichiers média nécessaires pour mettre en forme les widgets sur les pages.
Si vous appréciez les widgets de l’application Django Admin,
n’hésitez pas à les utiliser dans votre propre application! Ils sont tous stockés dans
in django.contrib.admin.widgets.
Quelle boite à outils JavaScript ?
Il existe beaucoup de boites à outils JavaScript, et la plupart contiennent des widgets (comme des widgets calendrier) utilisables pour améliorer votre application. Django a délibérément décidé de n’en privilégier aucune. Chaque boite à outils JavaScript a ses propres forces et faiblesses - utilisez celle qui correspond le mieux à vos besoins. Django est capable d’intégrer n’importe quelle boite à outils JavaScript.
La façon la plus simple de déclarer un média est de le faire dans une déclaration statique. Avec cette méthode, la déclaration média est dans une classe interne. Les propriétés de la classe interne définissent les besoins du média.
Voici un exemple simple:
class CalendarWidget(forms.TextInput):
class Media:
css = {
'all': ('pretty.css',)
}
js = ('animations.js', 'actions.js')
Ce code déclare un CalendarWidget, qui se basera sur un TextInput.
Chaque fois que le CalendarWidget est utilisé dans un formulaire, ce formulaire recevra l’ordre d’inclure le fichier CSS pretty.css, et les fichiers JavaScript animations.js et actions.js.
À l’exécution, cette déclaration statique de média est convertie en propriété widget nommée media. Le média d’une instance CalendarWidget peut être récupérée à travers cette propriété:
>>> w = CalendarWidget()
>>> print w.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
Voici la liste de toutes les options Media possibles. Il n’y en a aucune d’obligatoire.
css¶Un dictionnaire décrivant les fichiers CSS requis pour les différents types de sorties média.
Les valeurs de ce dictionnaire doivent être un tuple/liste de noms de fichiers. Voir la section sur les chemins media pour les détails sur la façon de spécifier les chemins vers les fichiers média.
Les clés du dictionnaire sont les types de sorties média. Ce sont les mêmes types que ceux acceptés par les fichiers CSS dans les déclarations media: ‘all’, ‘aural’, ‘braille’, ‘embossed’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’ et ‘tv’. Si vous avez besoin des feuilles de styles différentes pour différents types de média, fournissez une liste de fichiers CSS pour chaque type de médium de sortie. L’exemple suivant fournit deux options CSS – une pour les sorties écran, une autre pour l’impression:
class Media:
css = {
'screen': ('pretty.css',),
'print': ('newspaper.css',)
}
Si un groupe de fichiers CSS sont utilisables pour différents types de sorties média, le dictionnaire peut être une liste à virgule des types de sorties de médias. Dans l’exemple suivant, les TV et les projecteurs ont les mêmes besoins média:
class Media:
css = {
'screen': ('pretty.css',),
'tv,projector': ('lo_res.css',),
'print': ('newspaper.css',)
}
Si cette dernière définition CSS était mise en forme, elle deviendrait ce code HTML:
<link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
<link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
<link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
js¶Un tuple décrivant les fichiers JavaScript requis. Voir la section sur les chemins media pour les détails sur la façons de spécifier les chemins des fichiers média.
extend¶Un booléen définissant le comportement d’héritage des déclarations média.
Par défaut, tout objet utilisant une déclaration statique de média héritera de tous les médias associés au widget parent. Cela se produit indépendamment de la façon dont le parent déclare ses besoins média. Par exemple, si nous étendons notre widget Calendar de base de l’exemple précédent:
>>> class FancyCalendarWidget(CalendarWidget):
... class Media:
... css = {
... 'all': ('fancy.css',)
... }
... js = ('whizbang.js',)
>>> w = FancyCalendarWidget()
>>> print w.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
Le widget FancyCalendar hérite de tous les média de son widget parent. Si vous ne voulez pas cela, ajoutez une déclaration extend=False à la déclaration du media:
>>> class FancyCalendarWidget(CalendarWidget):
... class Media:
... extend = False
... css = {
... 'all': ('fancy.css',)
... }
... js = ('whizbang.js',)
>>> w = FancyCalendarWidget()
>>> print w.media
<link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
Si vous avez besoin de davantage de contrôle sur l’héritage de média, définissez votre média en utilisant une propriété dynamique. Les propriétés dynamiques vous donnent un contrôle complet sur les fichiers média qui sont hérités et sur ceux qui ne le sont pas.
Si vous avez besoin de faire des manipulations plus complexes sur les media, vous pouvez définir la propriété média directement. Définissez pour cela une propriété de widget qui renvoie une instance de forms.Media.
Le constructeur de forms.Media accepte des arguments mot-clé css et js dans le même format qui est utilisé dans la déclaration statique de media.
Par exemple, la déclaration statique de media de notre Widget Calendar Widget peut aussi être faite de façon dynamique:
class CalendarWidget(forms.TextInput):
def _media(self):
return forms.Media(css={'all': ('pretty.css',)},
js=('animations.js', 'actions.js'))
media = property(_media)
Voir la section Objets Media pour plus de détails sur la façon de construire des valeurs retour pour les propriétés media dynamiques.
Les chemins utilisés pour spécifier les média peuvent être absolus ou relatifs. Si le chemin débute par ‘/’, ‘http://‘ ou ‘https://‘, il sera interprété comme chemin absolu et laissé tel quel. Tous les autres chemins seront préfixés avec la valeur du préfixe approprié.
Dans le cadre de la mise en place des staticfiles app deux nouveaux paramètres ont été ajoutés pour faire référence aux “fichiers statiques” (images, CSS, Javascript, etc.) nécessaires pour produire une page web complète: STATIC_URL et STATIC_ROOT.
Pour trouver le préfixe adéquat, Django contrôlera si le paramètre
STATIC_URL n’est pas à None et se rabattra automatiquement sur l’utilisation de MEDIA_URL. Par exemple, si le MEDIA_URL de votre site est 'http://uploads.example.com/' et STATIC_URL est None:
>>> class CalendarWidget(forms.TextInput):
... class Media:
... css = {
... 'all': ('/css/pretty.css',),
... }
... js = ('animations.js', 'http://othersite.com/actions.js')
>>> w = CalendarWidget()
>>> print w.media
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://uploads.example.com/animations.js"></script>
<script type="text/javascript" src="http://othersite.com/actions.js"></script>
Mais si STATIC_URL est 'http://static.example.com/':
>>> w = CalendarWidget()
>>> print w.media
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://static.example.com/animations.js"></script>
<script type="text/javascript" src="http://othersite.com/actions.js"></script>
Lorsque vous interrogez l’attribut média d’un widget ou d’un formulaire, la valeur retournée est un objet forms.Media. Comme nous l’avons déjà vu, la représentation chaîne d’un objet Media est le code HTML nécessaire pour inclure le média dans le bloc <head> de votre page HTML.
Cependant, les objets Media ont quelques autres propriétés intéressantes.
Si vous ne voulez qu’un type particulier de média, vous pouvez utiliser l’opérateur indice pour filtrer celui qui vous intéresse. Par exemple:
>>> w = CalendarWidget()
>>> print w.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
>>> print w.media['css']
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
Lorsque vous utilisez l’opérateur indice, la valeur renvoyée est un nouvel objet Média – mais qui ne contient que le média qui vous intéresse.
Les objets Média peuvent aussi être additionnés. Lorsque deux objets médias sont additionnés, l’objet Média résultant contient l’union de médias des deux fichiers:
>>> class CalendarWidget(forms.TextInput):
... class Media:
... css = {
... 'all': ('pretty.css',)
... }
... js = ('animations.js', 'actions.js')
>>> class OtherWidget(forms.TextInput):
... class Media:
... js = ('whizbang.js',)
>>> w1 = CalendarWidget()
>>> w2 = OtherWidget()
>>> print w1.media + w2.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
Les widgets ne sont pas les seuls objets qui ont des déclarations média – les formulaires peuvent aussi déclarer des médias. Les règles des déclarations média des formulaires sont les mêmes que celles des widgets: les déclarations peuvent être statiques ou dynamiques; les chemins et les règles d’héritage de ces déclarations sont exactement les mêmes.
Que vous déclariez ou pas des médias, tous les objets Formulaire ont une propriété média. La valeur par défaut de cette propriété est la somme des déclarations média de tous les widgets du formulaire:
>>> class ContactForm(forms.Form):
... date = DateField(widget=CalendarWidget)
... name = CharField(max_length=40, widget=OtherWidget)
>>> f = ContactForm()
>>> f.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
Si vous voulez associer des médias supplémentaires à un formulaire – par exemple, du CSS pour la couche formulaire – ajoutez simplement une déclaration de media au formulaire:
>>> class ContactForm(forms.Form):
... date = DateField(widget=CalendarWidget)
... name = CharField(max_length=40, widget=OtherWidget)
...
... class Media:
... css = {
... 'all': ('layout.css',)
... }
>>> f = ContactForm()
>>> f.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
Aug 13, 2017