Spec-Zone.ru › Django 4.1

Аксессуары форм (класс Media)

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

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

Аксессуары и Django Admin

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

Если вам нравятся виджеты, которые использует приложение Django Admin, не стесняйтесь использовать их в своём приложении! Все они хранятся в 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" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script 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" media="screen" rel="stylesheet">
<link href="http://static.example.com/lo_res.css" media="tv,projector" rel="stylesheet">
<link href="http://static.example.com/newspaper.css" media="print" rel="stylesheet">
Изменено в Django 4.1:

В более ранних версиях атрибут type="text/css" включался в ссылки CSS.

js

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

extend

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

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

>>> 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" media="all" rel="stylesheet">
<link href="http://static.example.com/fancy.css" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script src="http://static.example.com/actions.js"></script>
<script 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" media="all" rel="stylesheet">
<script src="http://static.example.com/whizbang.js"></script>

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

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

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

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

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" media="all" rel="stylesheet">
<script src="http://uploads.example.com/animations.js"></script>
<script src="http://othersite.com/actions.js"></script>

Но если STATIC_URL является 'http://static.example.com/':

>>> w = CalendarWidget()
>>> print(w.media)
<link href="/css/pretty.css" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script src="http://othersite.com/actions.js"></script>

Или если staticfiles сконфигурировано с использованием ManifestStaticFilesStorage:

>>> w = CalendarWidget()
>>> print(w.media)
<link href="/css/pretty.css" media="all" rel="stylesheet">
<script src="https://static.example.com/animations.27e20196a850.js"></script>
<script src="http://othersite.com/actions.js"></script>

Пути в виде объектов

Новое в Django 4.1.

Пути к ресурсам также могут быть заданы в виде хешируемых объектов, реализующих метод __html__(). Метод __html__() обычно добавляется с помощью декоратора html_safe(). Объект отвечает за вывод содержимого полного HTML <script> или <link> тега:

>>> from django import forms
>>> from django.utils.html import html_safe
>>>
>>> @html_safe
>>> class JSPath:
...     def __str__(self):
...         return '<script src="https://example.org/asset.js" rel="stylesheet">'

>>> class SomeWidget(forms.TextInput):
...     class Media:
...         js = (JSPath(),)

Media объекты

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

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

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

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

>>> w = CalendarWidget()
>>> print(w.media)
<link href="http://static.example.com/pretty.css" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script src="http://static.example.com/actions.js"></script>

>>> print(w.media['css'])
<link href="http://static.example.com/pretty.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" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script src="http://static.example.com/actions.js"></script>
<script src="http://static.example.com/whizbang.js"></script>

Порядок ресурсов

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

Например:

>>> from django import forms
>>> class CalendarWidget(forms.TextInput):
...     class Media:
...         js = ('jQuery.js', 'calendar.js', 'noConflict.js')
>>> class TimeWidget(forms.TextInput):
...     class Media:
...         js = ('jQuery.js', 'time.js', 'noConflict.js')
>>> w1 = CalendarWidget()
>>> w2 = TimeWidget()
>>> print(w1.media + w2.media)
<script src="http://static.example.com/jQuery.js"></script>
<script src="http://static.example.com/calendar.js"></script>
<script src="http://static.example.com/time.js"></script>
<script src="http://static.example.com/noConflict.js"></script>

Объединение объектов Media с ресурсами в конфликтующем порядке приводит к MediaOrderConflictWarning.

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" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script src="http://static.example.com/actions.js"></script>
<script 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" media="all" rel="stylesheet">
<link href="http://static.example.com/layout.css" media="all" rel="stylesheet">
<script src="http://static.example.com/animations.js"></script>
<script src="http://static.example.com/actions.js"></script>
<script src="http://static.example.com/whizbang.js"></script>

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

Spec-Zone.ru

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