# Documentation Django 6.0.7

# Fichiers annexes de formulaire (classe `Media`)

L’affichage d’un formulaire Web attractif et ergonomique exige plus que du code HTML simple, il nécessite également des feuilles de style CSS, et si vous voulez utiliser des composants plaisants, il sera peut-être nécessaire d’inclure aussi du code JavaScript sur chaque page. La combinaison exacte de CSS et de JavaScript nécessaire pour une page donnée dépend des composants de formulaire employés sur cette page.

C’est là où la définition de fichiers annexes intervient. Django permet d’associer différents fichiers comme des feuilles de style et des scripts à des formulaires et des composants qui ont besoin de ces fichiers. Par exemple, si vous voulez utiliser un calendrier pour afficher les champs date, vous pouvez définir un composant `Calendrier` personnalisé. Ce composant peut ensuite être associé à des fichiers CSS et JavaScript requis pour afficher le calendrier. Quand le composant `Calendrier` est utilisé dans un formulaire, Django est capable d’identifier les fichiers CSS et JavaScript nécessaires et de fournir la liste des noms de fichiers au formulaire de manière à ce qu’ils puissent être inclus dans la page Web.

Fichiers annexes dans l’administration de Django

L’application d’administration de Django définit un certain nombre de composants personnalisés pour les calendriers, les sélections filtrées, etc. Ces composants définissent des exigences de fichiers annexes et l’administration de Django utilise ces composants personnalisés au lieu des composants par défaut de Django. Les gabarits de l’administration n’incluent que les fichiers nécessaires pour l’affichage des composants de la page en cours.

Si vous appréciez les composants utilisés par le site d’administration de Django, vous pouvez librement les utiliser dans votre propre application ! Ils se trouvent dans `django.contrib.admin.widgets`.

Quelle bibliothèque JavaScript ?

Il existe plusieurs bibliothèques JavaScript et beaucoup d’entre elles contiennent des composants utiles pour améliorer l’interface d’une application (comme par exemple des composants de calendrier). Django a délibérément évité de choisir parmi ces bibliothèques JavaScript. Chacune a ses forces et ses faiblesses, utilisez donc celle qui correspond à vos besoins. Django est capable d’intégrer n’importe quelle bibliothèque JavaScript.

## Fichiers annexes définis statiquement

La façon la plus simple de définir des fichiers annexes est sous forme de définition statique. Avec cette méthode, la déclaration se fait dans une classe `Media` interne. Les propriétés de la classe interne définissent les exigences.

Voici un exemple :

    from django import forms

    class CalendarWidget(forms.TextInput):
        class Media:
            css = {
                "all": ["pretty.css"],
            }
            js = ["animations.js", "actions.js"]

Ce code définit un composant `CalendarWidget`, qui est basé sur `TextInput`. Chaque fois que `CalendarWidget` sera utilisé dans un formulaire, ce dernier sera amené à inclure le fichier CSS `pretty.css` et les fichiers JavaScript `animations.js` et `actions.js`.

Cette définition statique est convertie au moment de l’exécution en une propriété de composant nommée `media`. La liste des fichiers annexes d’une instance de composant `CalendarWidget` peut être obtenue par cette propriété :

    >>> w = CalendarWidget()
    >>> print(w.media)
    <link href="https://static.example.com/pretty.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://static.example.com/actions.js"></script>

Voici une liste de toutes les options possibles de `Media`. Il n’y a pas d’option obligatoire.

### `css`

Un dictionnaire décrivant les fichiers CSS requis par les différentes formes de support d’affichage.

Les valeurs du dictionnaire doivent être composées de tuples/listes de noms de fichiers. Consultez la section sur les chemins pour plus de détails sur la manière de définir les chemins de ces fichiers.

Les clés du dictionnaire correspondent aux types de support d’affichage. Ce sont les mêmes types que les fichiers CSS acceptent dans les déclarations « media » : “all”, “aural”, “braille”, “embossed”, “handheld”, “print”, “projection”, “screen”, “tty” and “tv”. Si vous avez besoin de feuilles de style différentes en fonction de types de support différents, indiquez des listes de fichiers CSS correspondant à chacun de ces types. L’exemple suivant fournit deux options CSS, une pour l’affichage à l’écran et l’autre pour l’impression :

    class Media:
        css = {
            "screen": ["pretty.css"],
            "print": ["newspaper.css"],
        }

Si un groupe de fichiers CSS convient à plusieurs types de support d’affichage, la clé de dictionnaire peut être une liste de types de support d’affichage séparés par des virgules. Dans l’exemple suivant, les télévisions et les projecteurs ont les mêmes exigences en terme de support :

    class Media:
        css = {
            "screen": ["pretty.css"],
            "tv,projector": ["lo_res.css"],
            "print": ["newspaper.css"],
        }

Si cette dernière définition de CSS devait être affichée, cela produirait le code HTML suivant :

    <link href="https://static.example.com/pretty.css" media="screen" rel="stylesheet">
    <link href="https://static.example.com/lo_res.css" media="tv,projector" rel="stylesheet">
    <link href="https://static.example.com/newspaper.css" media="print" rel="stylesheet">

#### `Stylesheet` objects

New in Django 6.1.

class Stylesheet(href, **attributes)

  Represents a stylesheet link. The `rel` attribute is set to `"stylesheet"`.

  The first parameter, `href`, is the string path to the stylesheet file. See the section on paths for details on how to specify paths to these files.

  The optional keyword arguments, `**attributes`, are additional HTML attributes set on the rendered `<link>` tag.

  Voir Chemins sous forme d’objets pour des exemples d’utilisation.

### `js`

Un tuple décrivant les fichiers JavaScript nécessaires. Consultez la section sur les chemins pour plus de détails sur la manière de définir les chemins de ces fichiers.

#### Objets `Script`

class Script(src, **attributes)

  Représente un fichier de script.

  Le premier paramètre, `src`, est le chemin vers le fichier de script, au format texte. Consultez la section sur les chemins pour plus de détails sur la manière de définir les chemins de ces fichiers.

  Les arguments nommés optionnels, `**attributes`, sont des attributs HTML définis au moment du rendu de la balise `<script>`.

  Voir Chemins sous forme d’objets pour des exemples d’utilisation.

### `extend`

Une valeur booléenne définissant le comportement de l’héritage des déclarations `Media`.

Par défaut, tout objet utilisant une définition statique de `Media` hérite de tous les fichiers annexes associés au composant parent, et ceci quelle que soit la manière dont le parent définit ses propres exigences. Par exemple, si nous devions améliorer notre composant `Calendar` basique de l’exemple ci-dessus :

    >>> class FancyCalendarWidget(CalendarWidget):
    ...     class Media:
    ...         css = {
    ...             "all": ["fancy.css"],
    ...         }
    ...         js = ["whizbang.js"]
    ...

    >>> w = FancyCalendarWidget()
    >>> print(w.media)
    <link href="https://static.example.com/pretty.css" media="all" rel="stylesheet">
    <link href="https://static.example.com/fancy.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://static.example.com/actions.js"></script>
    <script src="https://static.example.com/whizbang.js"></script>

Le composant `FancyCalendar` hérite de tous les fichiers annexes de son composant parent. Si vous ne souhaitez pas que `Media` soit hérité de cette façon, ajoutez une déclaration `extend=False` à la déclaration de `Media`:

    >>> class FancyCalendarWidget(CalendarWidget):
    ...     class Media:
    ...         extend = False
    ...         css = {
    ...             "all": ["fancy.css"],
    ...         }
    ...         js = ["whizbang.js"]
    ...

    >>> w = FancyCalendarWidget()
    >>> print(w.media)
    <link href="https://static.example.com/fancy.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/whizbang.js"></script>

Si vous avez besoin de pouvoir contrôler encore plus l’héritage, définissez vos fichiers annexes en utilisant une propriété dynamique. Les propriétés dynamiques vous donnent un contrôle total sur les fichiers hérités et ceux qui ne le seront pas.

## `Media` comme propriété dynamique

Si vous avez besoin d’effectuer certaines manipulations encore plus sophistiquées sur les fichiers annexes requis, vous pouvez définir directement la propriété `media`. Cela peut être réalisé en définissant une propriété du composant qui renvoie une instance de `forms.Media`. le constructeur de `forms.Media` accepte les paramètres nommés `css` and `js` dans le même format que celui qui est utilisé pour les définitions statiques de fichiers annexes.

Par exemple, la définition statique de notre composant de calendrier pourrait tout aussi bien être réalisée de manière dynamique :

    class CalendarWidget(forms.TextInput):
        @property
        def media(self):
            return forms.Media(
                css={"all": ["pretty.css"]}, js=["animations.js", "actions.js"]
            )

Consultez la section sur les objets Media pour plus de détails sur la manière de construire des valeurs de retour pour les propriétés dynamiques `media`.

## Chemins dans les définitions de fichiers annexes

### Chemins sous forme de chaînes

Les chemins sous forme de chaînes utilisés pour définir les fichiers annexes peuvent être relatifs ou absolus. Si un chemin commence par `/`, `http://` ou `https://`, il sera interprété comme un chemin absolu et laissé tel quel. Tous les autres chemins seront préfixés par la valeur appropriée. Si l’application `django.contrib.staticfiles` est installée, elle sera utilisée pour servir ces fichiers.

Que l’application `django.contrib.staticfiles` soit utilisée ou non, les réglages `STATIC_URL` et `STATIC_ROOT` sont obligatoires pour produire une page Web complète.

Pour trouver le bon préfixe à utiliser, Django contrôle si le réglage `STATIC_URL` est différent de `None` et se rabat sur `MEDIA_URL` en cas de besoin. Par exemple, si le réglage `MEDIA_URL` de votre site est `'https://uploads.example.com/'` et que `STATIC_URL` vaut `None`:

    >>> from django import forms
    >>> class CalendarWidget(forms.TextInput):
    ...     class Media:
    ...         css = {
    ...             "all": ["/css/pretty.css"],
    ...         }
    ...         js = ["animations.js", "https://othersite.com/actions.js"]
    ...

    >>> w = CalendarWidget()
    >>> print(w.media)
    <link href="/css/pretty.css" media="all" rel="stylesheet">
    <script src="https://uploads.example.com/animations.js"></script>
    <script src="https://othersite.com/actions.js"></script>

Mai si `STATIC_URL` vaut `'https://static.example.com/'`:

    >>> w = CalendarWidget()
    >>> print(w.media)
    <link href="/css/pretty.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://othersite.com/actions.js"></script>

Ou si `staticfiles` est configuré avec le stockage `ManifestStaticFilesStorage`:

    >>> w = CalendarWidget()
    >>> print(w.media)
    <link href="/css/pretty.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.27e20196a850.js"></script>
    <script src="https://othersite.com/actions.js"></script>

### Chemins sous forme d’objets

Assets may also be object-based, using `Script` or `Stylesheet`. These allow you to pass custom HTML attributes:

    class Media:
        js = [
            Script(
                "https://cdn.example.com/something.min.js",
                **{
                    "crossorigin": "anonymous",
                    "async": True,
                },
            ),
        ]

Si cette définition `Media` devait être produite en HTML, cela donnerait :

    <script src="https://cdn.example.com/something.min.js"
            crossorigin="anonymous"
            async>
    </script>

Similarly, a `Stylesheet` object can be used to add a stylesheet link with custom HTML attributes:

    class Media:
        css = {
            "all": [
                Stylesheet(
                    "https://cdn.example.com/print.css",
                    crossorigin="anonymous",
                    media="print",
                ),
            ]
        }

If this Media definition were to be rendered, it would become:

    <link href="https://cdn.example.com/print.css"
          crossorigin="anonymous"
          media="print"
          rel="stylesheet">

## Objets `Media`

class Media

  Represents a collection of media assets required by a widget or form.

Lorsque vous interrogez l’attribut `media` d’un composant ou d’un formulaire, la valeur renvoyée est un objet `forms.Media`. Comme nous l’avons déjà vu, la représentation textuelle d’un objet `Media` contient le code HTML nécessaire pour inclure les fichiers concernés dans le bloc `<head>` de votre page HTML.

Cependant, les objets `Media` ont certaines autres propriétés intéressantes.

### Sous-ensembles de fichiers annexes

Si vous ne souhaitez obtenir que les fichiers d’un type particulier, vous pouvez utiliser l’opérateur d’indice pour filtrer le support qui vous intéresse. Par exemple :

    >>> w = CalendarWidget()
    >>> print(w.media)
    <link href="https://static.example.com/pretty.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://static.example.com/actions.js"></script>

    >>> print(w.media["css"])
    <link href="https://static.example.com/pretty.css" media="all" rel="stylesheet">

Lorsque vous employez l’opérateur d’indice, la valeur renvoyée est un nouvel objet `Media`, mais qui ne contient que les fichiers qui vous intéressent.

### Combinaison d’objets `Media`

Les objets `Media` peuvent aussi être fusionnés. Lorsque l’on additionne deux objets `Media`, l’objet `Media` résultant contient l’union des fichiers annexes contenus dans les deux objets :

    >>> from django import forms
    >>> 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="https://static.example.com/pretty.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://static.example.com/actions.js"></script>
    <script src="https://static.example.com/whizbang.js"></script>

### Ordre des fichiers annexes

L’ordre dans lequel les fichiers annexes sont insérés dans le DOM est souvent important. Par exemple, vous pourriez avoir un script dépendant de jQuery. Ainsi, la combinaison d’objets `Media` tente de conserver l’ordre relatif dans lequel les fichiers annexes sont définis dans chaque classe `Media`.

Par exemple :

    >>> from django import forms
    >>> class CalendarWidget(forms.TextInput):
    ...     class Media:
    ...         js = ["jQuery.js", "calendar.js", "noConflict.js"]
    ...
    >>> class TimeWidget(forms.TextInput):
    ...     class Media:
    ...         js = ["jQuery.js", "time.js", "noConflict.js"]
    ...
    >>> w1 = CalendarWidget()
    >>> w2 = TimeWidget()
    >>> print(w1.media + w2.media)
    <script src="https://static.example.com/jQuery.js"></script>
    <script src="https://static.example.com/calendar.js"></script>
    <script src="https://static.example.com/time.js"></script>
    <script src="https://static.example.com/noConflict.js"></script>

La combinaison d’objets `Media` ayant des fichiers annexes dans un ordre conflictuel produit un avertissement `MediaOrderConflictWarning`.

## `Media` pour les formulaires

Les composants ne sont pas les seuls objets qui peuvent posséder des définitions `media`, les formulaires peuvent aussi en définir. Les règles concernant les définitions `media` des formulaires sont les mêmes que pour les composants : les déclarations peuvent être statiques ou dynamiques ; les règles des chemins et de l’héritage de ces déclarations sont également identiques.

Que vous définissiez une déclaration `media` ou non, tous les objets `Form` possèdent une propriété `media`. La valeur par défaut de cette propriété est le résultat de la fusion de toutes les définitions `media` de tous les composants du formulaire :

    >>> from django import forms
    >>> class ContactForm(forms.Form):
    ...     date = DateField(widget=CalendarWidget)
    ...     name = CharField(max_length=40, widget=OtherWidget)
    ...

    >>> f = ContactForm()
    >>> f.media
    <link href="https://static.example.com/pretty.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://static.example.com/actions.js"></script>
    <script src="https://static.example.com/whizbang.js"></script>

Si vous souhaitez associer des fichiers annexes supplémentaires à un formulaire, par exemple des règles CSS pour la mise en forme du formulaire, ajoutez une déclaration `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="https://static.example.com/pretty.css" media="all" rel="stylesheet">
    <link href="https://static.example.com/layout.css" media="all" rel="stylesheet">
    <script src="https://static.example.com/animations.js"></script>
    <script src="https://static.example.com/actions.js"></script>
    <script src="https://static.example.com/whizbang.js"></script>