Ticket #4418: newforms-admin-media.diff

File newforms-admin-media.diff, 27.2 KB (added by russellm, 8 years ago)

Media descriptors for newforms-admin; against [5636]

  • django/newforms/formsets.py

     
    11from forms import Form, ValidationError
    22from fields import IntegerField, BooleanField
    3 from widgets import HiddenInput
     3from widgets import HiddenInput, Media
    44
    55# special field names
    66FORM_COUNT_FIELD_NAME = 'COUNT'
     
    149149        self.full_clean()
    150150        return self._is_valid
    151151
     152    def _get_media(self):
     153        # All the forms on a FormSet are the same, so you only need to
     154        # interrogate the first form for media.
     155        if self.forms:
     156            return self.forms[0].media
     157        else:
     158            return Media()
     159    media = property(_get_media)
     160   
    152161def formset_for_form(form, formset=BaseFormSet, num_extra=1, orderable=False, deletable=False):
    153162    """Return a FormSet for the given form class."""
    154163    attrs = {'form_class': form, 'num_extra': num_extra, 'orderable': orderable, 'deletable': deletable}
  • django/newforms/forms.py

     
    99from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
    1010
    1111from fields import Field
    12 from widgets import TextInput, Textarea
     12from widgets import Media, TextInput, Textarea
    1313from util import flatatt, ErrorDict, ErrorList, ValidationError
    1414
    1515__all__ = ('BaseForm', 'Form')
     
    234234        self.is_bound = False
    235235        self.__errors = None
    236236
     237    def _get_media(self):
     238        """
     239        Provide a description of all media required to render the widgets on this form
     240        """
     241        media = Media()
     242        for field in self.fields.values():
     243            media = media + field.widget.media
     244        return media
     245    media = property(_get_media)
     246   
    237247class Form(BaseForm):
    238248    "A collection of Fields, plus their associated data."
    239249    # This is a separate class from BaseForm in order to abstract the way
  • django/newforms/widgets.py

     
    88    from sets import Set as set   # Python 2.3 fallback
    99
    1010from itertools import chain
     11from django.conf import settings
    1112from django.utils.datastructures import MultiValueDict
    1213from django.utils.html import escape
    1314from django.utils.translation import ugettext
     
    1516from util import flatatt
    1617
    1718__all__ = (
    18     'Widget', 'TextInput', 'PasswordInput',
     19    'Media', 'Widget', 'TextInput', 'PasswordInput',
    1920    'HiddenInput', 'MultipleHiddenInput',
    2021    'FileInput', 'Textarea', 'CheckboxInput',
    2122    'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
    2223    'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
    2324)
    2425
     26MEDIA_TYPES = ('css','js')
     27
     28class Media(StrAndUnicode):
     29    def __init__(self, media=None, **kwargs):
     30        if media:
     31            media_attrs = media.__dict__
     32            del media_attrs['__module__']
     33            del media_attrs['__doc__']
     34        else:
     35            media_attrs = kwargs
     36           
     37        self._css = {}
     38        self._js = []
     39       
     40        for name in MEDIA_TYPES:
     41            getattr(self, 'add_' + name)(media_attrs.pop(name, None))
     42
     43        # Any leftover attributes must be invalid.
     44        if media_attrs != {}:
     45            raise TypeError, "'class Media' has invalid attribute(s): %s" % ','.join(media_attrs.keys())
     46       
     47    def __unicode__(self):
     48        return self.render()
     49       
     50    def render(self):
     51        output = []
     52        for name in MEDIA_TYPES:
     53            output.extend(getattr(self, 'render_' + name)())
     54        return u'\n'.join(output)
     55       
     56    def render_js(self):
     57        output = []
     58        for path in self._js:
     59            output.append(u'<script type="text/javascript" src="%s"></script>' % self.absolute_path(path))
     60        return output
     61       
     62    def render_css(self):
     63        output = []
     64        # To keep rendering order consistent, we can't just iterate over items().
     65        # We need to sort the keys, and iterate over the sorted list.
     66        media = self._css.keys()
     67        media.sort()
     68        for medium in media:
     69            for path in self._css[medium]:
     70                output.append(u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' % (self.absolute_path(path), medium))
     71        return output
     72       
     73    def absolute_path(self, path):
     74        return (path.startswith(u'http://') or path.startswith(u'https://')) and path or u''.join([settings.MEDIA_URL,path])
     75
     76    def __getitem__(self, name):
     77        "Returns a Media object that only contains media of the given type"
     78        if name in MEDIA_TYPES:
     79            return Media(**{name: getattr(self, '_' + name)})
     80        raise KeyError('Unknown media type "%s"' % name)
     81
     82    def add_js(self, data):
     83        if data:   
     84            self._js.extend([path for path in data if path not in self._js])
     85           
     86    def add_css(self, data):
     87        if data:
     88            for medium, paths in data.items():
     89                self._css.setdefault(medium, []).extend([path for path in paths if path not in self._css[medium]])
     90
     91    def __add__(self, other):
     92        combined = Media()
     93        for name in MEDIA_TYPES:
     94            getattr(combined, 'add_' + name)(getattr(self, '_' + name, None))
     95            getattr(combined, 'add_' + name)(getattr(other, '_' + name, None))
     96        return combined
     97       
     98class WidgetBase(type):
     99    "Metaclass for all widgets"
     100    def __new__(cls, name, bases, attrs):       
     101        media_definition = attrs.pop('Media', None)
     102        media_property = attrs.pop('media', None)
     103       
     104        # If this class definition doesn't have a media definition,
     105        # search the base classes.
     106        if media_definition == None and media_property == None:
     107            for base in bases:
     108                media_definition = getattr(base, 'Media', None)
     109                media_property = getattr(base, 'media', None)
     110                if media_definition or media_property:
     111                    break;
     112
     113        new_class = type.__new__(cls, name, bases, attrs)
     114        setattr(new_class, 'media', media_property and media_property or Media(media_definition))
     115        return new_class
     116       
    25117class Widget(object):
     118    __metaclass__ = WidgetBase
    26119    is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
    27120
    28121    def __init__(self, attrs=None):
     
    377470        """
    378471        raise NotImplementedError('Subclasses must implement this method.')
    379472
     473    def _get_media(self):
     474        "Media for a multiwidget is the combination of all media of the subwidgets"
     475        media = Media()
     476        for w in self.widgets:
     477            media = media + w.media
     478        return media
     479    media = property(_get_media)
     480   
    380481class SplitDateTimeWidget(MultiWidget):
    381482    """
    382483    A Widget that splits datetime input into two <input type="text"> boxes.
     
    389490        if value:
    390491            return [value.date(), value.time()]
    391492        return [None, None]
     493   
     494 No newline at end of file
  • django/contrib/admin/options.py

     
    22from django import newforms as forms
    33from django.newforms.formsets import all_valid
    44from django.newforms.models import inline_formset
     5from django.newforms.widgets import Media
    56from django.contrib.admin import widgets
    67from django.core.exceptions import ImproperlyConfigured, PermissionDenied
    78from django.db import models
     
    4849    def first_field(self):
    4950        for bf in self.form:
    5051            return bf
     52           
     53    def _get_media(self):
     54        media = self.form.media
     55        for fs in self.fieldsets:
     56            media = media + fs.media
     57        return media
     58    media = property(_get_media)
    5159
    5260class Fieldset(object):
    5361    def __init__(self, name=None, fields=(), classes=(), description=None):
     
    5563        self.classes = u' '.join(classes)
    5664        self.description = description
    5765
     66    def _get_media(self):
     67        from django.conf import settings
     68        if 'collapse' in self.classes:
     69            return Media(js=['%sjs/admin/CollapsedFieldsets.js' % settings.ADMIN_MEDIA_PREFIX])
     70        return Media()
     71    media = property(_get_media)
     72   
    5873class BoundFieldset(object):
    5974    def __init__(self, form, fieldset):
    6075        self.form, self.fieldset = form, fieldset
     
    123138
    124139        # For DateFields, add a custom CSS class.
    125140        if isinstance(db_field, models.DateField):
    126             kwargs['widget'] = forms.TextInput(attrs={'class': 'vDateField', 'size': '10'})
     141            kwargs['widget'] = widgets.AdminDateWidget
    127142            return db_field.formfield(**kwargs)
    128143
    129144        # For TimeFields, add a custom CSS class.
    130145        if isinstance(db_field, models.TimeField):
    131             kwargs['widget'] = forms.TextInput(attrs={'class': 'vTimeField', 'size': '8'})
     146            kwargs['widget'] = widgets.AdminTimeWidget
    132147            return db_field.formfield(**kwargs)
    133148
    134149        # For ForeignKey or ManyToManyFields, use a special widget.
     
    194209        else:
    195210            return self.change_view(request, unquote(url))
    196211
    197     def javascript(self, request, fieldsets):
    198         """
    199         Returns a list of URLs to include via <script> statements.
     212    def media(self, request):
     213        from django.conf import settings
    200214
    201         The URLs can be absolute ('/js/admin/') or explicit
    202         ('http://example.com/foo.js').
    203         """
    204         from django.conf import settings
    205215        js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
    206216        if self.prepopulated_fields:
    207217            js.append('js/urlify.js')
    208         if self.opts.has_field_type(models.DateTimeField) or self.opts.has_field_type(models.TimeField) or self.opts.has_field_type(models.DateField):
    209             js.extend(['js/calendar.js', 'js/admin/DateTimeShortcuts.js'])
    210218        if self.opts.get_ordered_objects():
    211219            js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
    212220        if self.js:
    213221            js.extend(self.js)
    214222        if self.filter_vertical or self.filter_horizontal:
    215223            js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
    216         for fs in fieldsets:
    217             if 'collapse' in fs.classes:
    218                 js.append('js/admin/CollapsedFieldsets.js')
    219                 break
    220         prefix = settings.ADMIN_MEDIA_PREFIX
    221         return ['%s%s' % (prefix, url) for url in js]
    222 
    223     def javascript_add(self, request):
    224         return self.javascript(request, self.fieldsets_add(request))
    225 
    226     def javascript_change(self, request, obj):
    227         return self.javascript(request, self.fieldsets_change(request, obj))
    228 
     224       
     225        return Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
     226               
    229227    def fieldsets(self, request):
    230228        """
    231229        Generator that yields Fieldset objects for use on add and change admin
     
    244242
    245243    def fieldsets_add(self, request):
    246244        "Hook for specifying Fieldsets for the add form."
    247         for fs in self.fieldsets(request):
    248             yield fs
     245        return list(self.fieldsets(request))
    249246
    250247    def fieldsets_change(self, request, obj):
    251248        "Hook for specifying Fieldsets for the change form."
    252         for fs in self.fieldsets(request):
    253             yield fs
     249        return list(self.fieldsets(request))
    254250
    255251    def has_add_permission(self, request):
    256252        "Returns True if the given request has permission to add an object."
     
    433429                inline_formset = FormSet()
    434430                inline_formsets.append(inline_formset)
    435431
     432        adminForm = AdminForm(form, list(self.fieldsets_add(request)), self.prepopulated_fields)
     433        media = self.media(request) + adminForm.media
     434        for fs in inline_formsets:
     435            media = media + fs.media
     436           
    436437        c = template.RequestContext(request, {
    437438            'title': _('Add %s') % opts.verbose_name,
    438             'adminform': AdminForm(form, self.fieldsets_add(request), self.prepopulated_fields),
     439            'adminform': adminForm,
    439440            'is_popup': request.REQUEST.has_key('_popup'),
    440441            'show_delete': False,
    441             'javascript_imports': self.javascript_add(request),
     442            'media': media,
    442443            'bound_inlines': [BoundInline(i, fs) for i, fs in zip(self.inlines, inline_formsets)],
    443444        })
    444445        return render_change_form(self, model, model.AddManipulator(), c, add=True)
     
    500501                        #related.get_accessor_name())
    501502                #orig_list = func()
    502503                #oldform.order_objects.extend(orig_list)
     504               
     505        adminForm = AdminForm(form, self.fieldsets_change(request, obj), self.prepopulated_fields)       
     506        media = self.media(request) + adminForm.media
     507        for fs in inline_formsets:
     508            media = media + fs.media
     509           
    503510        c = template.RequestContext(request, {
    504511            'title': _('Change %s') % opts.verbose_name,
    505             'adminform': AdminForm(form, self.fieldsets_change(request, obj), self.prepopulated_fields),
     512            'adminform': adminForm,
    506513            'object_id': object_id,
    507514            'original': obj,
    508515            'is_popup': request.REQUEST.has_key('_popup'),
    509             'javascript_imports': self.javascript_change(request, obj),
     516            'media': media,
    510517            'bound_inlines': [BoundInline(i, fs) for i, fs in zip(self.inlines, inline_formsets)],
    511518        })
    512519        return render_change_form(self, model, model.ChangeManipulator(object_id), c, change=True)
  • django/contrib/admin/widgets.py

     
    55from django import newforms as forms
    66from django.utils.text import capfirst
    77from django.utils.translation import ugettext as _
     8from django.conf import settings
    89
    910class FilteredSelectMultiple(forms.SelectMultiple):
    1011    """
     
    2829            (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
    2930        return u''.join(output)
    3031
     32class AdminDateWidget(forms.TextInput):
     33    class Media:
     34        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
     35              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
     36       
     37    def __init__(self, attrs={}):
     38        super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'})
     39
     40class AdminTimeWidget(forms.TextInput):
     41    class Media:
     42        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
     43              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
     44
     45    def __init__(self, attrs={}):
     46        super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
     47   
    3148class AdminSplitDateTime(forms.SplitDateTimeWidget):
    3249    """
    3350    A SplitDateTime Widget that has some admin-specific styling.
    3451    """
    3552    def __init__(self, attrs=None):
    36         widgets = [forms.TextInput(attrs={'class': 'vDateField', 'size': '10'}),
    37                    forms.TextInput(attrs={'class': 'vTimeField', 'size': '8'})]
     53        widgets = [AdminDateWidget, AdminTimeWidget]
    3854        # Note that we're calling MultiWidget, not SplitDateTimeWidget, because
    3955        # we want to define widgets.
    4056        forms.MultiWidget.__init__(self, widgets, attrs)
  • django/contrib/admin/templates/admin/auth/user/change_password.html

     
    22{% load i18n admin_modify adminmedia %}
    33{% block extrahead %}{{ block.super }}
    44<script type="text/javascript" src="../../../../jsi18n/"></script>
    5 {% for js in javascript_imports %}{% include_admin_script js %}{% endfor %}
    65{% endblock %}
    76{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
    87{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
  • django/contrib/admin/templates/admin/change_form.html

     
    33
    44{% block extrahead %}{{ block.super }}
    55<script type="text/javascript" src="../../../jsi18n/"></script>
    6 {% for js in javascript_imports %}<script type="text/javascript" src="{{ js }}"></script>
    7 {% endfor %}
     6{{ media }}
    87{% endblock %}
    98
    109{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
  • tests/regressiontests/forms/media.py

     
     1# -*- coding: utf-8 -*-
     2# Tests for the media handling on widgets and forms
     3
     4media_tests = r"""
     5>>> from django.newforms import TextInput, Media, TextInput, CharField, Form, MultiWidget
     6>>> from django.conf import settings
     7>>> settings.MEDIA_URL = 'http://media.example.com'
     8
     9# A widget can exist without a media definition
     10>>> class MyWidget(TextInput):
     11...     pass
     12
     13>>> w = MyWidget()
     14>>> print w.media
     15<BLANKLINE>
     16
     17# A widget can define media if it needs to.
     18# Any absolute path will be preserved; relative paths are combined
     19# with the value of settings.MEDIA_URL
     20>>> class MyWidget1(TextInput):
     21...     class Media:
     22...         css = {
     23...            'all': ('/path/to/css1','/path/to/css2')
     24...         }
     25...         js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
     26
     27>>> w1 = MyWidget1()
     28>>> print w1.media
     29<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     30<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     31<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     32<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     33<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     34
     35# Media objects can be interrogated by media type
     36>>> print w1.media['css']
     37<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     38<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     39
     40>>> print w1.media['js']
     41<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     42<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     43<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     44
     45# Media objects can be combined. Any given media resource will appear only
     46# once. Duplicated media definitions are ignored.
     47>>> class MyWidget2(TextInput):
     48...     class Media:
     49...         css = {
     50...            'all': ('/path/to/css2','/path/to/css3')
     51...         }
     52...         js = ('/path/to/js1','/path/to/js4')
     53
     54>>> class MyWidget3(TextInput):
     55...     class Media:
     56...         css = {
     57...            'all': ('/path/to/css3','/path/to/css1')
     58...         }
     59...         js = ('/path/to/js1','/path/to/js4')
     60
     61>>> w2 = MyWidget2()
     62>>> w3 = MyWidget3()
     63>>> print w1.media + w2.media + w3.media
     64<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     65<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     66<link href="http://media.example.com/path/to/css3" type="text/css" media="all" rel="stylesheet" />
     67<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     68<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     69<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     70<script type="text/javascript" src="http://media.example.com/path/to/js4"></script>
     71
     72# Check that media addition hasn't affected the original objects
     73>>> print w1.media
     74<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     75<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     76<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     77<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     78<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     79
     80
     81# If a widget extends another, it inherits the parent widget's media
     82>>> class MyWidget4(MyWidget1):
     83...     pass
     84
     85>>> w4 = MyWidget4()
     86>>> print w4.media
     87<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     88<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     89<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     90<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     91<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     92
     93# If a widget extends another but defines media, it overrides the parent widget's media.
     94>>> class MyWidget5(MyWidget1):
     95...     class Media:
     96...         css = {
     97...            'all': ('/path/to/css3','/path/to/css1')
     98...         }
     99...         js = ('/path/to/js1','/path/to/js4')
     100
     101>>> w5 = MyWidget5()
     102>>> print w5.media
     103<link href="http://media.example.com/path/to/css3" type="text/css" media="all" rel="stylesheet" />
     104<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     105<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     106<script type="text/javascript" src="http://media.example.com/path/to/js4"></script>
     107
     108# You can ask a form for the media required by its widgets.
     109>>> class MyForm(Form):
     110...     field1 = CharField(max_length=20, widget=MyWidget1())
     111...     field2 = CharField(max_length=20, widget=MyWidget2())
     112>>> f1 = MyForm()
     113>>> print f1.media
     114<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     115<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     116<link href="http://media.example.com/path/to/css3" type="text/css" media="all" rel="stylesheet" />
     117<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     118<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     119<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     120<script type="text/javascript" src="http://media.example.com/path/to/js4"></script>
     121
     122# Form media can be combined to produce a single media definition.
     123>>> class AnotherForm(Form):
     124...     field3 = CharField(max_length=20, widget=MyWidget3())
     125>>> f2 = AnotherForm()
     126>>> print f1.media + f2.media
     127<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     128<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     129<link href="http://media.example.com/path/to/css3" type="text/css" media="all" rel="stylesheet" />
     130<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     131<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     132<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     133<script type="text/javascript" src="http://media.example.com/path/to/js4"></script>
     134
     135# Form media can be defined as a property, too
     136>>> class MyWidget6(TextInput):
     137...     def _media(self):
     138...         return Media(css={'all': ('/some/path',)})
     139...     media = property(_media)
     140
     141>>> w6 = MyWidget6()
     142>>> print w6.media
     143<link href="http://media.example.com/some/path" type="text/css" media="all" rel="stylesheet" />
     144
     145# You can extend media, if required.
     146>>> class MyWidget7(MyWidget6):
     147...     def _media(self):
     148...         return super(MyWidget7, self).media + Media(css={'all': ('/other/path',)})
     149...     media = property(_media)
     150
     151>>> w7 = MyWidget7()
     152>>> print w7.media
     153<link href="http://media.example.com/some/path" type="text/css" media="all" rel="stylesheet" />
     154<link href="http://media.example.com/other/path" type="text/css" media="all" rel="stylesheet" />
     155
     156# A widget can define CSS media for multiple output media types
     157>>> class MyWidget8(TextInput):
     158...     class Media:
     159...         css = {
     160...            'screen, print': ('/file1','/file2'),
     161...            'screen': ('/file3',),
     162...            'print': ('/file4',)
     163...         }
     164...         js = ('/path/to/js1','/path/to/js4')
     165
     166>>> w8 = MyWidget8()
     167>>> print w8.media
     168<link href="http://media.example.com/file4" type="text/css" media="print" rel="stylesheet" />
     169<link href="http://media.example.com/file3" type="text/css" media="screen" rel="stylesheet" />
     170<link href="http://media.example.com/file1" type="text/css" media="screen, print" rel="stylesheet" />
     171<link href="http://media.example.com/file2" type="text/css" media="screen, print" rel="stylesheet" />
     172<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     173<script type="text/javascript" src="http://media.example.com/path/to/js4"></script>
     174
     175# MultiWidgets have a default media definition that gets all the
     176# media from the component widgets
     177>>> class MyWidget9(MultiWidget):
     178...     def __init__(self, attrs=None):
     179...         widgets = [MyWidget1, MyWidget2, MyWidget3]
     180...         MultiWidget.__init__(self, widgets, attrs)
     181           
     182>>> w9 = MyWidget9()
     183>>> print w9.media           
     184<link href="http://media.example.com/path/to/css1" type="text/css" media="all" rel="stylesheet" />
     185<link href="http://media.example.com/path/to/css2" type="text/css" media="all" rel="stylesheet" />
     186<link href="http://media.example.com/path/to/css3" type="text/css" media="all" rel="stylesheet" />
     187<script type="text/javascript" src="http://media.example.com/path/to/js1"></script>
     188<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
     189<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
     190<script type="text/javascript" src="http://media.example.com/path/to/js4"></script>
     191
     192"""
     193 No newline at end of file
  • tests/regressiontests/forms/tests.py

     
    22from localflavor import localflavor_tests
    33from regressions import regression_tests
    44from formsets import formset_tests
     5from media import media_tests
    56
    67form_tests = r"""
    78>>> from django.newforms import *
     
    36983699    'localflavor': localflavor_tests,
    36993700    'regressions': regression_tests,
    37003701    'formset_tests': formset_tests,
     3702    'media_tests': media_tests,
    37013703}
    37023704
    37033705if __name__ == "__main__":
Back to Top