=================================Form Assets (the ``Media`` class)=================================Rendering an attractive and easy-to-use web form requires more than justHTML - it also requires CSS stylesheets, and if you want to use fancy widgets,you may also need to include some JavaScript on each page. The exactcombination of CSS and JavaScript that is required for any given page willdepend upon the widgets that are in use on that page.This is where asset definitions come in. Django allows you toassociate different files -- like stylesheets and scripts -- with theforms and widgets that require those assets. For example, if you wantto use a calendar to render DateFields, you can define a customCalendar widget. This widget can then be associated with the CSS andJavaScript that is required to render the calendar. When the Calendarwidget is used on a form, Django is able to identify the CSS andJavaScript files that are required, and provide the list of file namesin a form suitable for inclusion on your web page... admonition:: Assets and Django AdminThe Django Admin application defines a number of customizedwidgets for calendars, filtered selections, and so on. Thesewidgets define asset requirements, and the Django Admin uses thecustom widgets in place of the Django defaults. The Admintemplates will only include those files that are required torender the widgets on any given page.If you like the widgets that the Django Admin application uses,feel free to use them in your own application! They're all storedin ``django.contrib.admin.widgets``... admonition:: Which JavaScript toolkit?Many JavaScript toolkits exist, and many of them include widgets (suchas calendar widgets) that can be used to enhance your application.Django has deliberately avoided blessing any one JavaScript toolkit.Each toolkit has its own relative strengths and weaknesses - usewhichever toolkit suits your requirements. Django is able to integratewith any JavaScript toolkit... _assets-as-a-static-definition:Assets as a static definition=============================The easiest way to define assets is as a static definition. Using thismethod, the declaration is an inner ``Media`` class. The properties of theinner class define the requirements.Here's an example::from django import formsclass CalendarWidget(forms.TextInput):class Media:css = {'all': ('pretty.css',)}js = ('animations.js', 'actions.js')This code defines a ``CalendarWidget``, which will be based on ``TextInput``.Every time the CalendarWidget is used on a form, that form will be directedto include the CSS file ``pretty.css``, and the JavaScript files``animations.js`` and ``actions.js``.This static definition is converted at runtime into a widget propertynamed ``media``. The list of assets for a ``CalendarWidget`` instancecan be retrieved through this property::>>> w = CalendarWidget()>>> print(w.media)<link href="http://static.example.com/pretty.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://static.example.com/actions.js"></script>Here's a list of all possible ``Media`` options. There are no required options.``css``-------A dictionary describing the CSS files required for various forms of outputmedia.The values in the dictionary should be a tuple/list of file names. See:ref:`the section on paths <form-asset-paths>` for details of how tospecify paths to these files.The keys in the dictionary are the output media types. These are the sametypes accepted by CSS files in media declarations: 'all', 'aural', 'braille','embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. Ifyou need to have different stylesheets for different media types, providea list of CSS files for each output medium. The following example wouldprovide two CSS options -- one for the screen, and one for print::class Media:css = {'screen': ('pretty.css',),'print': ('newspaper.css',)}If a group of CSS files are appropriate for multiple output media types,the dictionary key can be a comma separated list of output media types.In the following example, TV's and projectors will have the same mediarequirements::class Media:css = {'screen': ('pretty.css',),'tv,projector': ('lo_res.css',),'print': ('newspaper.css',)}If this last CSS definition were to be rendered, it would become the following HTML::<link href="http://static.example.com/pretty.css" media="screen" rel="stylesheet"><link href="http://static.example.com/lo_res.css" media="tv,projector" rel="stylesheet"><link href="http://static.example.com/newspaper.css" media="print" rel="stylesheet">.. versionchanged:: 4.1In older versions, the ``type="text/css"`` attribute is included in CSSlinks.``js``------A tuple describing the required JavaScript files. See :ref:`thesection on paths <form-asset-paths>` for details of how to specifypaths to these files.``extend``----------A boolean defining inheritance behavior for ``Media`` declarations.By default, any object using a static ``Media`` definition willinherit all the assets associated with the parent widget. This occursregardless of how the parent defines its own requirements. Forexample, if we were to extend our basic Calendar widget from theexample above::>>> class FancyCalendarWidget(CalendarWidget):... class Media:... css = {... 'all': ('fancy.css',)... }... js = ('whizbang.js',)>>> w = FancyCalendarWidget()>>> print(w.media)<link href="http://static.example.com/pretty.css" media="all" rel="stylesheet"><link href="http://static.example.com/fancy.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://static.example.com/actions.js"></script><script src="http://static.example.com/whizbang.js"></script>The FancyCalendar widget inherits all the assets from its parentwidget. If you don't want ``Media`` to be inherited in this way, addan ``extend=False`` declaration to the ``Media`` declaration::>>> class FancyCalendarWidget(CalendarWidget):... class Media:... extend = False... css = {... 'all': ('fancy.css',)... }... js = ('whizbang.js',)>>> w = FancyCalendarWidget()>>> print(w.media)<link href="http://static.example.com/fancy.css" media="all" rel="stylesheet"><script src="http://static.example.com/whizbang.js"></script>If you require even more control over inheritance, define your assets using a:ref:`dynamic property <dynamic-property>`. Dynamic properties give youcomplete control over which files are inherited, and which are not... _dynamic-property:``Media`` as a dynamic property===============================If you need to perform some more sophisticated manipulation of assetrequirements, you can define the ``media`` property directly. This isdone by defining a widget property that returns an instance of``forms.Media``. The constructor for ``forms.Media`` accepts ``css``and ``js`` keyword arguments in the same format as that used in astatic media definition.For example, the static definition for our Calendar Widget could alsobe defined in a dynamic fashion::class CalendarWidget(forms.TextInput):@propertydef media(self):return forms.Media(css={'all': ('pretty.css',)},js=('animations.js', 'actions.js'))See the section on `Media objects`_ for more details on how to constructreturn values for dynamic ``media`` properties... _form-asset-paths:Paths in asset definitions==========================Paths as strings----------------String paths used to specify assets can be either relative or absolute. If apath starts with ``/``, ``http://`` or ``https://``, it will beinterpreted as an absolute path, and left as-is. All other paths willbe prepended with the value of the appropriate prefix. If the:mod:`django.contrib.staticfiles` app is installed, it will be used to serveassets.Whether or not you use :mod:`django.contrib.staticfiles`, the:setting:`STATIC_URL` and :setting:`STATIC_ROOT` settings are required torender a complete web page.To find the appropriate prefix to use, Django will check if the:setting:`STATIC_URL` setting is not ``None`` and automatically fall backto using :setting:`MEDIA_URL`. For example, if the :setting:`MEDIA_URL` foryour site was ``'http://uploads.example.com/'`` and :setting:`STATIC_URL`was ``None``::>>> from django import forms>>> 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" media="all" rel="stylesheet"><script src="http://uploads.example.com/animations.js"></script><script src="http://othersite.com/actions.js"></script>But if :setting:`STATIC_URL` is ``'http://static.example.com/'``::>>> w = CalendarWidget()>>> print(w.media)<link href="/css/pretty.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://othersite.com/actions.js"></script>Or if :mod:`~django.contrib.staticfiles` is configured using the:class:`~django.contrib.staticfiles.storage.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="http://othersite.com/actions.js"></script>Paths as objects----------------.. versionadded:: 4.1Asset paths may also be given as hashable objects implementing an``__html__()`` method. The ``__html__()`` method is typically added using the:func:`~django.utils.html.html_safe` decorator. The object is responsible foroutputting the complete HTML ``<script>`` or ``<link>`` tag content::>>> from django import forms>>> from django.utils.html import html_safe>>>>>> @html_safe>>> class JSPath:... def __str__(self):... return '<script src="https://example.org/asset.js" rel="stylesheet">'>>> class SomeWidget(forms.TextInput):... class Media:... js = (JSPath(),)``Media`` objects=================When you interrogate the ``media`` attribute of a widget or form, thevalue that is returned is a ``forms.Media`` object. As we have alreadyseen, the string representation of a ``Media`` object is the HTMLrequired to include the relevant files in the ``<head>`` block of yourHTML page.However, ``Media`` objects have some other interesting properties.Subsets of assets-----------------If you only want files of a particular type, you can use the subscriptoperator to filter out a medium of interest. For example::>>> w = CalendarWidget()>>> print(w.media)<link href="http://static.example.com/pretty.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://static.example.com/actions.js"></script>>>> print(w.media['css'])<link href="http://static.example.com/pretty.css" media="all" rel="stylesheet">When you use the subscript operator, the value that is returned is anew ``Media`` object -- but one that only contains the media of interest.Combining ``Media`` objects---------------------------``Media`` objects can also be added together. When two ``Media`` objects areadded, the resulting ``Media`` object contains the union of the assetsspecified by both::>>> 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="http://static.example.com/pretty.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://static.example.com/actions.js"></script><script src="http://static.example.com/whizbang.js"></script>.. _form-media-asset-order:Order of assets---------------The order in which assets are inserted into the DOM is often important. Forexample, you may have a script that depends on jQuery. Therefore, combining``Media`` objects attempts to preserve the relative order in which assets aredefined in each ``Media`` class.For example::>>> 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="http://static.example.com/jQuery.js"></script><script src="http://static.example.com/calendar.js"></script><script src="http://static.example.com/time.js"></script><script src="http://static.example.com/noConflict.js"></script>Combining ``Media`` objects with assets in a conflicting order results in a``MediaOrderConflictWarning``.``Media`` on Forms==================Widgets aren't the only objects that can have ``media`` definitions --forms can also define ``media``. The rules for ``media`` definitionson forms are the same as the rules for widgets: declarations can bestatic or dynamic; path and inheritance rules for those declarationsare exactly the same.Regardless of whether you define a ``media`` declaration, *all* Formobjects have a ``media`` property. The default value for this propertyis the result of adding the ``media`` definitions for all widgets thatare part of the form::>>> 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="http://static.example.com/pretty.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://static.example.com/actions.js"></script><script src="http://static.example.com/whizbang.js"></script>If you want to associate additional assets with a form -- for example,CSS for form layout -- add a ``Media`` declaration to the form::>>> 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://static.example.com/pretty.css" media="all" rel="stylesheet"><link href="http://static.example.com/layout.css" media="all" rel="stylesheet"><script src="http://static.example.com/animations.js"></script><script src="http://static.example.com/actions.js"></script><script src="http://static.example.com/whizbang.js"></script>