表单资产(Media
类)¶
渲染一个有吸引力和易于使用的Web窗体不仅仅需要HTML - 它还需要CSS样式表,如果你想使用漂亮的“Web2.0”小部件,你可能还需要在每个页面上包含一些JavaScript。任何给定页面所需的CSS和JavaScript的确切组合将取决于该页面上使用的小部件。
这就是资产定义的地方。Django允许您将不同的文件(如样式表和脚本)与需要这些资产的窗体和窗口小部件相关联。例如,如果要使用日历来渲染DateField,您可以定义自定义日历窗口小部件。然后,此窗口小部件可以与呈现日历所需的CSS和JavaScript相关联。当在窗体上使用日历小部件时,Django能够识别所需的CSS和JavaScript文件,并以适合于轻松包含在Web页面中的形式提供文件名列表。
资产和Django管理员
Django Admin应用程序为日历,过滤的选择等定义了一些定制的小部件。这些小部件定义资产要求,Django Admin使用自定义小部件来代替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')
这段代码定义了一个基于 TextInput
的 CalendarWidget
。每次在表单上使用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文件接受的相同类型:“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" />
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 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
以这种方式继承,请在 Media
声明中添加一个 extend=False
声明:
>>> 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
的实例的widget属性来完成。 forms.Media
的构造函数以与静态媒体定义中使用的格式相同的格式接受 css
和 js
关键字参数。
例如,我们的Calendar Widget的静态定义也可以动态定义:
class CalendarWidget(forms.TextInput):
def _media(self):
return forms.Media(css={'all': ('pretty.css',)},
js=('animations.js', 'actions.js'))
media = property(_media)
有关如何为动态 media
属性构造返回值的更多详细信息,请参阅 Media objects 部分。
资产定义中的路径¶
用于指定资产的路径可以是相对的或绝对的。如果路径以 /
,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 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>
或者如果使用 ~django.contib.staticfiles.ManifestStaticFilesStorage 配置 staticfiles
:
>>> 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.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
声明,all 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>