parts/django/docs/topics/forms/media.txt
changeset 307 c6bca38c1cbf
equal deleted inserted replaced
306:5ff1fc726848 307:c6bca38c1cbf
       
     1 Form Media
       
     2 ==========
       
     3 
       
     4 Rendering an attractive and easy-to-use Web form requires more than just
       
     5 HTML - it also requires CSS stylesheets, and if you want to use fancy
       
     6 "Web2.0" widgets, you may also need to include some JavaScript on each
       
     7 page. The exact combination of CSS and JavaScript that is required for
       
     8 any given page will depend upon the widgets that are in use on that page.
       
     9 
       
    10 This is where Django media definitions come in. Django allows you to
       
    11 associate different media files with the forms and widgets that require
       
    12 that media. For example, if you want to use a calendar to render DateFields,
       
    13 you can define a custom Calendar widget. This widget can then be associated
       
    14 with the CSS and JavaScript that is required to render the calendar. When
       
    15 the Calendar widget is used on a form, Django is able to identify the CSS and
       
    16 JavaScript files that are required, and provide the list of file names
       
    17 in a form suitable for easy inclusion on your Web page.
       
    18 
       
    19 .. admonition:: Media and Django Admin
       
    20 
       
    21     The Django Admin application defines a number of customized widgets
       
    22     for calendars, filtered selections, and so on. These widgets define
       
    23     media requirements, and the Django Admin uses the custom widgets
       
    24     in place of the Django defaults. The Admin templates will only include
       
    25     those media files that are required to render the widgets on any
       
    26     given page.
       
    27 
       
    28     If you like the widgets that the Django Admin application uses,
       
    29     feel free to use them in your own application! They're all stored
       
    30     in ``django.contrib.admin.widgets``.
       
    31 
       
    32 .. admonition:: Which JavaScript toolkit?
       
    33 
       
    34     Many JavaScript toolkits exist, and many of them include widgets (such
       
    35     as calendar widgets) that can be used to enhance your application.
       
    36     Django has deliberately avoided blessing any one JavaScript toolkit.
       
    37     Each toolkit has its own relative strengths and weaknesses - use
       
    38     whichever toolkit suits your requirements. Django is able to integrate
       
    39     with any JavaScript toolkit.
       
    40 
       
    41 Media as a static definition
       
    42 ----------------------------
       
    43 
       
    44 The easiest way to define media is as a static definition. Using this method,
       
    45 the media declaration is an inner class. The properties of the inner class
       
    46 define the media requirements.
       
    47 
       
    48 Here's a simple example::
       
    49 
       
    50     class CalendarWidget(forms.TextInput):
       
    51         class Media:
       
    52             css = {
       
    53                 'all': ('pretty.css',)
       
    54             }
       
    55             js = ('animations.js', 'actions.js')
       
    56 
       
    57 This code defines a ``CalendarWidget``, which will be based on ``TextInput``.
       
    58 Every time the CalendarWidget is used on a form, that form will be directed
       
    59 to include the CSS file ``pretty.css``, and the JavaScript files
       
    60 ``animations.js`` and ``actions.js``.
       
    61 
       
    62 This static media definition is converted at runtime into a widget property
       
    63 named ``media``. The media for a CalendarWidget instance can be retrieved
       
    64 through this property::
       
    65 
       
    66     >>> w = CalendarWidget()
       
    67     >>> print w.media
       
    68     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
    69     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
    70     <script type="text/javascript" src="http://media.example.com/actions.js"></script>
       
    71 
       
    72 Here's a list of all possible ``Media`` options. There are no required options.
       
    73 
       
    74 ``css``
       
    75 ~~~~~~~
       
    76 
       
    77 A dictionary describing the CSS files required for various forms of output
       
    78 media.
       
    79 
       
    80 The values in the dictionary should be a tuple/list of file names. See
       
    81 `the section on media paths`_ for details of how to specify paths to media
       
    82 files.
       
    83 
       
    84 .. _the section on media paths: `Paths in media definitions`_
       
    85 
       
    86 The keys in the dictionary are the output media types. These are the same
       
    87 types accepted by CSS files in media declarations: 'all', 'aural', 'braille',
       
    88 'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. If
       
    89 you need to have different stylesheets for different media types, provide
       
    90 a list of CSS files for each output medium. The following example would
       
    91 provide two CSS options -- one for the screen, and one for print::
       
    92 
       
    93     class Media:
       
    94         css = {
       
    95             'screen': ('pretty.css',),
       
    96             'print': ('newspaper.css',)
       
    97         }
       
    98 
       
    99 If a group of CSS files are appropriate for multiple output media types,
       
   100 the dictionary key can be a comma separated list of output media types.
       
   101 In the following example, TV's and projectors will have the same media
       
   102 requirements::
       
   103 
       
   104     class Media:
       
   105         css = {
       
   106             'screen': ('pretty.css',),
       
   107             'tv,projector': ('lo_res.css',),
       
   108             'print': ('newspaper.css',)
       
   109         }
       
   110 
       
   111 If this last CSS definition were to be rendered, it would become the following HTML::
       
   112 
       
   113     <link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
       
   114     <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
       
   115     <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
       
   116 
       
   117 ``js``
       
   118 ~~~~~~
       
   119 
       
   120 A tuple describing the required JavaScript files. See
       
   121 `the section on media paths`_ for details of how to specify paths to media
       
   122 files.
       
   123 
       
   124 ``extend``
       
   125 ~~~~~~~~~~
       
   126 
       
   127 A boolean defining inheritance behavior for media declarations.
       
   128 
       
   129 By default, any object using a static media definition will inherit all the
       
   130 media associated with the parent widget. This occurs regardless of how the
       
   131 parent defines its media requirements. For example, if we were to extend our
       
   132 basic Calendar widget from the example above::
       
   133 
       
   134     >>> class FancyCalendarWidget(CalendarWidget):
       
   135     ...     class Media:
       
   136     ...         css = {
       
   137     ...             'all': ('fancy.css',)
       
   138     ...         }
       
   139     ...         js = ('whizbang.js',)
       
   140 
       
   141     >>> w = FancyCalendarWidget()
       
   142     >>> print w.media
       
   143     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   144     <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
       
   145     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
   146     <script type="text/javascript" src="http://media.example.com/actions.js"></script>
       
   147     <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
       
   148 
       
   149 The FancyCalendar widget inherits all the media from it's parent widget. If
       
   150 you don't want media to be inherited in this way, add an ``extend=False``
       
   151 declaration to the media declaration::
       
   152 
       
   153     >>> class FancyCalendarWidget(CalendarWidget):
       
   154     ...     class Media:
       
   155     ...         extend = False
       
   156     ...         css = {
       
   157     ...             'all': ('fancy.css',)
       
   158     ...         }
       
   159     ...         js = ('whizbang.js',)
       
   160 
       
   161     >>> w = FancyCalendarWidget()
       
   162     >>> print w.media
       
   163     <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
       
   164     <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
       
   165 
       
   166 If you require even more control over media inheritance, define your media
       
   167 using a `dynamic property`_. Dynamic properties give you complete control over
       
   168 which media files are inherited, and which are not.
       
   169 
       
   170 .. _dynamic property: `Media as a dynamic property`_
       
   171 
       
   172 Media as a dynamic property
       
   173 ---------------------------
       
   174 
       
   175 If you need to perform some more sophisticated manipulation of media
       
   176 requirements, you can define the media property directly. This is done
       
   177 by defining a widget property that returns an instance of ``forms.Media``.
       
   178 The constructor for ``forms.Media`` accepts ``css`` and ``js`` keyword
       
   179 arguments in the same format as that used in a static media definition.
       
   180 
       
   181 For example, the static media definition for our Calendar Widget could
       
   182 also be defined in a dynamic fashion::
       
   183 
       
   184     class CalendarWidget(forms.TextInput):
       
   185         def _media(self):
       
   186             return forms.Media(css={'all': ('pretty.css',)},
       
   187                                js=('animations.js', 'actions.js'))
       
   188         media = property(_media)
       
   189 
       
   190 See the section on `Media objects`_ for more details on how to construct
       
   191 return values for dynamic media properties.
       
   192 
       
   193 Paths in media definitions
       
   194 --------------------------
       
   195 
       
   196 Paths used to specify media can be either relative or absolute. If a path
       
   197 starts with '/', 'http://' or 'https://', it will be interpreted as an absolute
       
   198 path, and left as-is. All other paths will be prepended with the value of
       
   199 ``settings.MEDIA_URL``. For example, if the MEDIA_URL for your site was
       
   200 ``http://media.example.com/``::
       
   201 
       
   202     class CalendarWidget(forms.TextInput):
       
   203         class Media:
       
   204             css = {
       
   205                 'all': ('/css/pretty.css',),
       
   206             }
       
   207             js = ('animations.js', 'http://othersite.com/actions.js')
       
   208 
       
   209     >>> w = CalendarWidget()
       
   210     >>> print w.media
       
   211     <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   212     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
   213     <script type="text/javascript" src="http://othersite.com/actions.js"></script>
       
   214 
       
   215 Media objects
       
   216 -------------
       
   217 
       
   218 When you interrogate the media attribute of a widget or form, the value that
       
   219 is returned is a ``forms.Media`` object. As we have already seen, the string
       
   220 representation of a Media object is the HTML required to include media
       
   221 in the ``<head>`` block of your HTML page.
       
   222 
       
   223 However, Media objects have some other interesting properties.
       
   224 
       
   225 Media subsets
       
   226 ~~~~~~~~~~~~~
       
   227 
       
   228 If you only want media of a particular type, you can use the subscript operator
       
   229 to filter out a medium of interest. For example::
       
   230 
       
   231     >>> w = CalendarWidget()
       
   232     >>> print w.media
       
   233     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   234     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
   235     <script type="text/javascript" src="http://media.example.com/actions.js"></script>
       
   236 
       
   237     >>> print w.media['css']
       
   238     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   239 
       
   240 When you use the subscript operator, the value that is returned is a new
       
   241 Media object -- but one that only contains the media of interest.
       
   242 
       
   243 Combining media objects
       
   244 ~~~~~~~~~~~~~~~~~~~~~~~
       
   245 
       
   246 Media objects can also be added together. When two media objects are added,
       
   247 the resulting Media object contains the union of the media from both files::
       
   248 
       
   249     >>> class CalendarWidget(forms.TextInput):
       
   250     ...     class Media:
       
   251     ...         css = {
       
   252     ...             'all': ('pretty.css',)
       
   253     ...         }
       
   254     ...         js = ('animations.js', 'actions.js')
       
   255 
       
   256     >>> class OtherWidget(forms.TextInput):
       
   257     ...     class Media:
       
   258     ...         js = ('whizbang.js',)
       
   259 
       
   260     >>> w1 = CalendarWidget()
       
   261     >>> w2 = OtherWidget()
       
   262     >>> print w1.media + w2.media
       
   263     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   264     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
   265     <script type="text/javascript" src="http://media.example.com/actions.js"></script>
       
   266     <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
       
   267 
       
   268 Media on Forms
       
   269 --------------
       
   270 
       
   271 Widgets aren't the only objects that can have media definitions -- forms
       
   272 can also define media. The rules for media definitions on forms are the
       
   273 same as the rules for widgets: declarations can be static or dynamic;
       
   274 path and inheritance rules for those declarations are exactly the same.
       
   275 
       
   276 Regardless of whether you define a media declaration, *all* Form objects
       
   277 have a media property. The default value for this property is the result
       
   278 of adding the media definitions for all widgets that are part of the form::
       
   279 
       
   280     >>> class ContactForm(forms.Form):
       
   281     ...     date = DateField(widget=CalendarWidget)
       
   282     ...     name = CharField(max_length=40, widget=OtherWidget)
       
   283 
       
   284     >>> f = ContactForm()
       
   285     >>> f.media
       
   286     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   287     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
   288     <script type="text/javascript" src="http://media.example.com/actions.js"></script>
       
   289     <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
       
   290 
       
   291 If you want to associate additional media with a form -- for example, CSS for form
       
   292 layout -- simply add a media declaration to the form::
       
   293 
       
   294     >>> class ContactForm(forms.Form):
       
   295     ...     date = DateField(widget=CalendarWidget)
       
   296     ...     name = CharField(max_length=40, widget=OtherWidget)
       
   297     ...
       
   298     ...     class Media:
       
   299     ...         css = {
       
   300     ...             'all': ('layout.css',)
       
   301     ...         }
       
   302 
       
   303     >>> f = ContactForm()
       
   304     >>> f.media
       
   305     <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
       
   306     <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
       
   307     <script type="text/javascript" src="http://media.example.com/animations.js"></script>
       
   308     <script type="text/javascript" src="http://media.example.com/actions.js"></script>
       
   309     <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>