Spec-Zone.ru › Django 1.11

Формы и ресурсы (класс Media)

Для создания привлекательной и удобной формы веб-приложения требуется не только HTML, но и CSS-стили, а для использования современных виджетов «веб 2.0» может потребоваться также JavaScript на каждой странице. Точное сочетание CSS и JavaScript, необходимое для каждой страницы, зависит от используемых на ней виджетов.

Здесь на помощь приходят определения ресурсов. Django позволяет связывать разные файлы — например, таблицы стилей и скрипты — с формами и виджетами, которым эти ресурсы нужны. Например, если вы хотите использовать календарь для отображения полей DateField, вы можете определить пользовательский виджет Calendar. Этот виджет можно связать с CSS и JavaScript, необходимыми для отображения календаря. Когда виджет Calendar используется в форме, Django может определить необходимые CSS и JavaScript-файлы и предоставить список имён файлов в формате, удобном для лёгкой интеграции в вашу веб-страницу.

Ресурсы и администрирование Django

Приложение администрирования Django определяет ряд настроенных виджетов для календарей, фильтрованных выборов и т. д. Эти виджеты определяют требования к ресурсам, и приложение администрирования Django использует настроенные виджеты вместо стандартных виджетов Django. Шаблоны администрирования включают только те файлы, которые необходимы для отображения виджетов на конкретной странице.

Если вам нравятся виджеты, используемые приложением администрирования Django, вы можете использовать их в своём приложении! Все они хранятся в django.contrib.admin.widgets.

Какой JavaScript-фреймворк использовать?

Существует множество JavaScript-фреймворков, многие из которых включают виджеты (такие как календари), которые можно использовать для улучшения вашего приложения. Django намеренно не поддерживает какой-либо конкретный JavaScript-фреймворк. Каждый фреймворк имеет свои преимущества и недостатки — используйте тот, который подходит вашим потребностям. Django может интегрироваться с любым JavaScript-фреймворком.

Ресурсы как статическое определение

Самый простой способ определения ресурсов — это статическое определение. С помощью этого метода объявление находится внутри Media класса. Свойства внутреннего класса определяют требования.

Вот простой пример:

from django import forms

class CalendarWidget(forms.TextInput):
    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js', 'actions.js')

Этот код определяет CalendarWidget, который будет базироваться на TextInput. Каждый раз, когда виджет CalendarWidget используется в форме, эта форма будет включена в CSS-файл pretty.css, а также в JavaScript-файлы animations.js и actions.js.

Это статическое определение в ходе выполнения преобразуется в свойство виджета с именем media. Список ресурсов для экземпляра CalendarWidget можно получить через это свойство:

>>> 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>

Вот список всех возможных Media опций. Требуемых опций нет.

css

Словарь, описывающий требуемые CSS-файлы для различных типов вывода.

Значения в словаре должны быть кортежами/списками имён файлов. Подробности о том, как указать пути к этим файлам, см. в разделе путей.

Ключами в словаре являются типы вывода. Это те же типы, которые принимают CSS-файлы в объявлениях media: «all», «aural», «braille», «embossed», «handheld», «print», «projection», «screen», «tty» и «tv». Если вам нужны разные таблицы стилей для разных типов вывода, предоставьте список CSS-файлов для каждого типа вывода. Следующий пример предоставит две CSS-опции — одну для экрана и одну для печати:

class Media:
    css = {
        'screen': ('pretty.css',),
        'print': ('newspaper.css',)
    }

Если группа CSS-файлов подходит для нескольких типов вывода, ключ словаря может быть списком типов вывода, разделённых запятыми. В следующем примере у телевизоров и проекторов будут одинаковые требования к ресурсам:

class Media:
    css = {
        'screen': ('pretty.css',),
        'tv,projector': ('lo_res.css',),
        'print': ('newspaper.css',)
    }

Если это последнее определение CSS будет отображено, оно превратится в следующий 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

Кортеж, описывающий необходимые JavaScript-файлы. Подробности о том, как указать пути к этим файлам, см. в разделе путей.

extend

Булево значение, определяющее поведение наследования для Media объявлений.

По умолчанию любой объект, использующий статическое Media определение, наследует все ресурсы, связанные с родительским виджетом. Это происходит независимо от того, как родитель определяет свои собственные требования. Например, если мы расширим наш базовый виджет Calendar из примера выше:

>>> 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>

Виджет FancyCalendar наследует все ресурсы от своего родительского виджета. Если вы не хотите, чтобы Media наследуется таким образом, добавьте объявление extend=False в объявление Media.

>>> 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>

Если вам нужен больший контроль над наследованием, определите свои ресурсы, используя динамическое свойство. Динамические свойства дают вам полный контроль над тем, какие файлы наследуются, а какие нет.

Media как динамическое свойство

Если вам нужно произвести более сложные манипуляции с требованиями к ресурсам, вы можете определить свойство media непосредственно. Это делается путём определения свойства виджета, которое возвращает экземпляр forms.Media. Конструктор для forms.Media принимает css и js ключевые аргументы в том же формате, что и при статическом определении ресурсов.

Например, статическое определение нашего виджета Calendar можно определить и динамически:

class CalendarWidget(forms.TextInput):
    @property
    def media(self):
        return forms.Media(css={'all': ('pretty.css',)},
                           js=('animations.js', 'actions.js'))

См. раздел объектов Media для получения дополнительной информации о том, как создавать возвращаемые значения для динамических media свойств.

Пути в определениях ресурсов

Пути, используемые для указания ресурсов, могут быть относительными или абсолютными. Если путь начинается с /, http:// или https://, он будет интерпретироваться как абсолютный путь и останется неизменным. Все остальные пути будут дополняться значением соответствующего префикса. Если приложение django.contrib.staticfiles установлено, оно будет использоваться для обслуживания ресурсов.

Используете ли вы django.contrib.staticfiles, или нет, настройки STATIC_URL и STATIC_ROOT необходимы для полной отрисовки веб-страницы.

Чтобы найти соответствующий префикс, Django проверит, не является ли настройка STATIC_URL пустой и автоматически вернётся к использованию MEDIA_URL. Например, если MEDIA_URL вашего сайта было 'http://uploads.example.com/' и STATIC_URL было None.

>>> from django import forms
>>> 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>

Но если STATIC_URL является '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>

Или если staticfiles настроено с помощью ManifestStaticFilesStorage.

>>> w = CalendarWidget()
>>> print(w.media)
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="https://static.example.com/animations.27e20196a850.js"></script>
<script type="text/javascript" src="http://othersite.com/actions.js"></script>
Изменено в Django 1.10:

В более старых версиях ресурсы не обслуживались с помощью django.contrib.staticfiles.

Media объекты

При обращении к атрибуту media виджета или формы возвращается объект forms.Media. Как мы уже видели, строковое представление объекта Media — это HTML, необходимый для включения соответствующих файлов в блок <head> вашей HTML-страницы.

Однако у объектов Media есть и другие интересные свойства.

Подмножества ресурсов

Если вам нужны только файлы определённого типа, вы можете использовать оператор индексации для фильтрации интересующего вас типа. Например:

>>> 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" />

При использовании оператора индексации возвращается новый объект Media — но содержащий только интересующие ресурсы.

Объединение объектов Media

Объекты Media также могут быть объединены. Когда два объекта Media складываются, получившийся объект Media содержит объединение ресурсов, указанных в обоих:

>>> from django import forms
>>> 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 в формах

Виджеты — не единственные объекты, которые могут иметь media определения — формы также могут определять media. Правила для media определений в формах такие же, как для виджетов: определения могут быть статическими или динамическими; правила путей и наследования для этих определений абсолютно одинаковы.

Независимо от того, определяете ли вы media объявление, все объекты Form имеют свойство media. Значение по умолчанию для этого свойства — результат сложения media определений для всех виджетов, которые являются частью формы:

>>> from django import forms
>>> 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>

Если вы хотите связать дополнительные ресурсы с формой — например, CSS для макета формы — просто добавьте Media объявление в форму:

>>> 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>

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.11/topics/forms/media/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API