media.txt 13 KB

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