Форма Assets ( Mediaкласс)

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

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

Активы и администратор Django

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

Если вам нравятся виджеты, которые использует приложение 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" type="text/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 в объявлениях мультимедиа: 'all', 'aural', 'braille', 'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' и ' Телевизор'. Если вам нужно иметь разные таблицы стилей для разных типов мультимедиа, предоставьте список файлов 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определение, наследует все активы, связанные с родительским виджетом. Это происходит независимо от того, как родитель определяет свои собственные требования. Например, если бы мы расширили наш базовый виджет Календаря из приведенного выше примера:

>>> 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 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" type="text/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свойств.

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

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

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

Чтобы найти подходящий префикс для использования, Django проверит, не установлен ли этот STATIC_URLпараметр, Noneи автоматически вернется к использованию 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 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" type="text/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" type="text/css" media="all" rel="stylesheet">
<script src="https://static.example.com/animations.27e20196a850.js"></script>
<script src="http://othersite.com/actions.js"></script>

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 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" 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 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" type="text/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" type="text/css" media="all" rel="stylesheet">
<link href="http://static.example.com/layout.css" type="text/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>

Copyright ©2021 All rights reserved