django.forms-Widget和Media间的联系

来源:互联网 发布:大数据,银行风险 编辑:程序博客网 时间:2024/06/06 16:44
Media的作用是引用js和css的, 用来修饰Widget的。它们之间通过Widget定义media属性或内置Media类来联系的。

先引用一个官网的例子:

?
1
2
3
4
5
6
7
8
from django import formsclass 
 
CalendarWidget(forms.TextInput):
    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js''actions.js')

这是通过内置Media类来实现js和css引用的。

下面讲解,它实例化的顺序

首先看Widget类的定义:

?
1
2
class Widget(six.with_metaclass(MediaDefiningClass)):
    ......

   with_metaclass()方法返回一个通过元类动态生成的类。

然后看元类MediaDefiningClass的定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
class MediaDefiningClass(type):
    """
    Metaclass for classes that can have media definitions.
    """
    def __new__(mcs, name, bases, attrs):
        new_class = (super(MediaDefiningClass, mcs)
            .__new__(mcs, name, bases, attrs))
 
        if 'media' not in attrs:
            new_class.media = media_property(new_class)
 
        return new_class

通过复写__new__方法,来动态添加media属性。

它首先会判断Widget类有没有media属性, 没有就通过media_property()方法添加。


接着来探究media_property()方法是如何添加media属性的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def media_property(cls):
    def _media(self):
        # Get the media property of the superclass, if it exists
        sup_cls = super(clsself)
        try:
            base = sup_cls.media
        except AttributeError:
            base = Media()
 
        # Get the media definition for this class
        definition = getattr(cls'Media'None)
        if definition:
            extend = getattr(definition, 'extend'True)
            if extend:
                if extend is True:
                    = base
                else:
                    = Media()
                    for medium in extend:
                        = + base[medium]
                return + Media(definition)
            else:
                return Media(definition)
        else:
            return base
    return property(_media)

因为涉及到继承的原因, 所以会有些复杂。media的继承是通过制定extend属性。

media默认会自动继承父类, 也可以设置extend = False取消继承。当然也可以指定extend = ( 'js' )或着( 'css' ,  'js' ),

选择性的继承某部分。


首先它会获取父类的media,否则返回空的media。然后根据extend的值,来添加继承的部分。

然后结合内置Media类的属性,返回最后的media。

最后返回经过property()包装的_media函数。

property()是经常用来包装对属性的访问。可以看出,我们通过Widget.media访问media属性,获取到的是动态生成的。

这也意味着,每次返回的结果都是同一个media。可以通过id( )函数测试。


以上都是通过内置Media类来达到对js和css的引用。还有种方法是直接定义media。

仍旧引用官网的例子:

?
1
2
3
4
5
class CalendarWidget(forms.TextInput):
    def _media(self):
        return forms.Media(css={'all': ('pretty.css',)},
                           js=('animations.js''actions.js'))
    media = property(_media)

这样同样可以达到相同的效果, 但是不能继承。

还有个优点是,我们可以制定返回的是新的media对象, 也可以是同一个media对象。


0 0
原创粉丝点击