mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	git-svn-id: http://code.djangoproject.com/svn/django/trunk@15369 bcc190cf-cafb-0310-a4f2-bffc1f526a37
		
			
				
	
	
		
			333 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			333 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| Form Media
 | |
| ==========
 | |
| 
 | |
| Rendering an attractive and easy-to-use Web form requires more than just
 | |
| HTML - it also requires CSS stylesheets, and if you want to use fancy
 | |
| "Web2.0" widgets, you may also need to include some JavaScript on each
 | |
| page. The exact combination of CSS and JavaScript that is required for
 | |
| any given page will depend upon the widgets that are in use on that page.
 | |
| 
 | |
| This is where Django media definitions come in. Django allows you to
 | |
| associate different media files with the forms and widgets that require
 | |
| that media. For example, if you want to use a calendar to render DateFields,
 | |
| you can define a custom Calendar widget. This widget can then be associated
 | |
| with the CSS and JavaScript that is required to render the calendar. When
 | |
| the Calendar widget is used on a form, Django is able to identify the CSS and
 | |
| JavaScript files that are required, and provide the list of file names
 | |
| in a form suitable for easy inclusion on your Web page.
 | |
| 
 | |
| .. admonition:: Media and Django Admin
 | |
| 
 | |
|     The Django Admin application defines a number of customized widgets
 | |
|     for calendars, filtered selections, and so on. These widgets define
 | |
|     media requirements, and the Django Admin uses the custom widgets
 | |
|     in place of the Django defaults. The Admin templates will only include
 | |
|     those media files that are required to render 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 stored
 | |
|     in ``django.contrib.admin.widgets``.
 | |
| 
 | |
| .. admonition:: Which JavaScript toolkit?
 | |
| 
 | |
|     Many JavaScript toolkits exist, and many of them include widgets (such
 | |
|     as 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 - use
 | |
|     whichever toolkit suits your requirements. Django is able to integrate
 | |
|     with any JavaScript toolkit.
 | |
| 
 | |
| Media as a static definition
 | |
| ----------------------------
 | |
| 
 | |
| The easiest way to define media is as a static definition. Using this method,
 | |
| the media declaration is an inner class. The properties of the inner class
 | |
| define the media requirements.
 | |
| 
 | |
| Here's a simple example::
 | |
| 
 | |
|     class 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 directed
 | |
| to include the CSS file ``pretty.css``, and the JavaScript files
 | |
| ``animations.js`` and ``actions.js``.
 | |
| 
 | |
| This static media definition is converted at runtime into a widget property
 | |
| named ``media``. The media for a CalendarWidget instance can be retrieved
 | |
| through this property::
 | |
| 
 | |
|     >>> 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>
 | |
| 
 | |
| 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 output
 | |
| media.
 | |
| 
 | |
| The values in the dictionary should be a tuple/list of file names. See
 | |
| `the section on media paths`_ for details of how to specify paths to media
 | |
| files.
 | |
| 
 | |
| .. _the section on media paths: `Paths in media definitions`_
 | |
| 
 | |
| The keys in the dictionary are the output media types. These are the same
 | |
| types accepted by CSS files in media declarations: 'all', 'aural', 'braille',
 | |
| 'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. If
 | |
| you need to have different stylesheets for different media types, provide
 | |
| a list of CSS files for each output medium. The following example would
 | |
| provide 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 media
 | |
| requirements::
 | |
| 
 | |
|     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://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``
 | |
| ~~~~~~
 | |
| 
 | |
| A tuple describing the required JavaScript files. See
 | |
| `the section on media paths`_ for details of how to specify paths to media
 | |
| files.
 | |
| 
 | |
| ``extend``
 | |
| ~~~~~~~~~~
 | |
| 
 | |
| A boolean defining inheritance behavior for media declarations.
 | |
| 
 | |
| By default, any object using a static media definition will inherit all the
 | |
| media associated with the parent widget. This occurs regardless of how the
 | |
| parent defines its media requirements. For example, if we were to extend our
 | |
| basic Calendar widget from the example above::
 | |
| 
 | |
|     >>> 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>
 | |
| 
 | |
| The FancyCalendar widget inherits all the media from it's parent widget. If
 | |
| you don't want media to be inherited in this way, add an ``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://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
 | |
|     <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
 | |
| 
 | |
| If you require even more control over media inheritance, define your media
 | |
| using a `dynamic property`_. Dynamic properties give you complete control over
 | |
| which media files are inherited, and which are not.
 | |
| 
 | |
| .. _dynamic property: `Media as a dynamic property`_
 | |
| 
 | |
| Media as a dynamic property
 | |
| ---------------------------
 | |
| 
 | |
| If you need to perform some more sophisticated manipulation of media
 | |
| requirements, you can define the media property directly. This is done
 | |
| 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 a static media definition.
 | |
| 
 | |
| For example, the static media definition for our Calendar Widget could
 | |
| also be defined in a dynamic fashion::
 | |
| 
 | |
|     class CalendarWidget(forms.TextInput):
 | |
|         def _media(self):
 | |
|             return forms.Media(css={'all': ('pretty.css',)},
 | |
|                                js=('animations.js', 'actions.js'))
 | |
|         media = property(_media)
 | |
| 
 | |
| See the section on `Media objects`_ for more details on how to construct
 | |
| return values for dynamic media properties.
 | |
| 
 | |
| .. _form-media-paths:
 | |
| 
 | |
| Paths in media definitions
 | |
| --------------------------
 | |
| 
 | |
| .. versionchanged:: 1.3
 | |
| 
 | |
| Paths used to specify media can be either relative or absolute. If a path
 | |
| starts with '/', 'http://' or 'https://', it will be interpreted as an absolute
 | |
| path, and left as-is. All other paths will be prepended with the value of
 | |
| the appropriate prefix.
 | |
| 
 | |
| As part of the introduction of the
 | |
| :doc:`staticfiles app </ref/contrib/staticfiles>` two new settings were added
 | |
| to refer to "static files" (images, CSS, Javascript, etc.) that are needed
 | |
| to render a complete web page: :setting:`STATIC_URL` and :setting:`STATIC_ROOT`.
 | |
| 
 | |
| To find the appropriate prefix to use, Django will check if the
 | |
| :setting:`STATIC_URL` setting is not ``None`` and automatically fall back
 | |
| to using :setting:`MEDIA_URL`. For example, if the :setting:`MEDIA_URL` for
 | |
| your site was ``'http://uploads.example.com/'`` and :setting:`STATIC_URL`
 | |
| was ``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>
 | |
| 
 | |
| But if :setting:`STATIC_URL` is ``'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>
 | |
| 
 | |
| 
 | |
| Media objects
 | |
| -------------
 | |
| 
 | |
| When you interrogate the media attribute of a widget or form, the value that
 | |
| is returned is a ``forms.Media`` object. As we have already seen, the string
 | |
| representation of a Media object is the HTML required to include media
 | |
| in the ``<head>`` block of your HTML page.
 | |
| 
 | |
| However, Media objects have some other interesting properties.
 | |
| 
 | |
| Media subsets
 | |
| ~~~~~~~~~~~~~
 | |
| 
 | |
| If you only want media of a particular type, you can use the subscript operator
 | |
| to filter out a medium of interest. For example::
 | |
| 
 | |
|     >>> 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" />
 | |
| 
 | |
| When you use the subscript operator, the value that is returned is a new
 | |
| 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 are added,
 | |
| the resulting Media object contains the union of the media from both files::
 | |
| 
 | |
|     >>> 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>
 | |
| 
 | |
| Media on Forms
 | |
| --------------
 | |
| 
 | |
| Widgets aren't the only objects that can have media definitions -- forms
 | |
| can also define media. The rules for media definitions on forms are the
 | |
| same as the rules for widgets: declarations can be static or dynamic;
 | |
| path and inheritance rules for those declarations are exactly the same.
 | |
| 
 | |
| Regardless of whether you define a media declaration, *all* Form objects
 | |
| have a media property. The default value for this property is the result
 | |
| of adding the media definitions for all widgets that are part of the form::
 | |
| 
 | |
|     >>> 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>
 | |
| 
 | |
| If you want to associate additional media with a form -- for example, CSS for form
 | |
| layout -- simply 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://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>
 |