123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- 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://static.example.com/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://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 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://static.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
- <link href="http://static.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
- <link href="http://static.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://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <link href="http://static.example.com/fancy.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://static.example.com/actions.js"></script>
- <script type="text/javascript" src="http://static.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://static.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://static.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://static.example.com/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://static.example.com/actions.js"></script>
- >>> print(w.media)['css']
- <link href="http://static.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://static.example.com/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://static.example.com/actions.js"></script>
- <script type="text/javascript" src="http://static.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://static.example.com/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://static.example.com/actions.js"></script>
- <script type="text/javascript" src="http://static.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://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <link href="http://static.example.com/layout.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://static.example.com/actions.js"></script>
- <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
|