dajngo.forms.widget-Media

来源:互联网 发布:大数据分析技术 编辑:程序博客网 时间:2024/06/14 09:07
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
MEDIA_TYPES = ('css''js')
 
class Media(object):
    def __init__(self, media=None**kwargs):
        if media:
            media_attrs = media.__dict__
        else:
            media_attrs = kwargs
 
        self._css = {}
        self._js = []
 
        for name in MEDIA_TYPES:
            getattr(self'add_' + name)(media_attrs.get(name, None))
 
    def __str__(self):
        return self.render()
 
    def render(self):
        return mark_safe('\n'.join(chain(*[getattr(self'render_' + name)() for name in MEDIA_TYPES])))
 
    def render_js(self):
        return [
            format_html(
                '<script type="text/javascript" src="{0}"></script>',
                self.absolute_path(path)
            for path in self._js
        ]
 
    def render_css(self):
        # To keep rendering order consistent, we can't just iterate over items().
        # We need to sort the keys, and iterate over the sorted list.
        media = sorted(self._css.keys())
        return chain(*[[
            format_html(
                '<link href="{0}" type="text/css" media="{1}" rel="stylesheet" />',
                self.absolute_path(path), medium
            for path in self._css[medium]
        for medium in media])
 
    def absolute_path(self, path, prefix=None):
        if path.startswith(('http://''https://''/')):
            return path
        if prefix is None:
            if settings.STATIC_URL is None:
                # backwards compatibility
                prefix = settings.MEDIA_URL
            else:
                prefix = settings.STATIC_URL
        return urljoin(prefix, path)
 
    def __getitem__(self, name):
        "Returns a Media object that only contains media of the given type"
        if name in MEDIA_TYPES:
            return Media(**{str(name): getattr(self'_' + name)})
        raise KeyError('Unknown media type "%s"' % name)
 
    def add_js(self, data):
        if data:
            for path in data:
                if path not in self._js:
                    self._js.append(path)
 
    def add_css(self, data):
        if data:
            for medium, paths in data.items():
                for path in paths:
                    if not self._css.get(medium) or path not in self._css[medium]:
                        self._css.setdefault(medium, []).append(path)
 
    def __add__(self, other):
        combined = Media()
        for name in MEDIA_TYPES:
            getattr(combined, 'add_' + name)(getattr(self'_' + name, None))
            getattr(combined, 'add_' + name)(getattr(other, '_' + name, None))
        return combined

Media负责对js和css的引用。

属性self._js = [], self._css = {} 分别负责js和css的文件引用。

方法add_js,add_css负责添加文件引用。

方法render_js, render_css负责输出引用js和css的html语句。


通过对add_js(self,  data)方法的分析, 可以看出参数data的格式是['js_path_1', 'js_path_2']。self._js的格式也是由js文件名组成的列表。

通过对add_css(self, data)方法的分析, 可以看参数data的格式为

{'medium_type_1': ['type_1_path_1', 'type_1_path_2',....], 

'medium_type_2': ['type_2_path_1', ...]

....}。

self._css的格式也是由medium:paths组成的字典。paths是由path组成的列表。


通过调用方法的形式,

?
1
2
getattr(self'add_' + name),
getattr(self'render_' + name)

可以看到都是由

?
1
MEDIA_TYPES = ('css''js')

来命名的。


我们可以看到render()和render_css()都使用了chain方法。

首先来看render_css(), 

?
1
2
3
4
5
6
chain(*[[
            format_html(
                '<link href="{0}" type="text/css" media="{1}" rel="stylesheet" />',
                self.absolute_path(path), medium
            for path in self._css[medium]
        for medium in media])


看嵌套列表表达式

?
1
2
3
4
5
6
[[
            format_html(
                '<link href="{0}" type="text/css" media="{1}" rel="stylesheet" />',
                self.absolute_path(path), medium
            for path in self._css[medium]
        for medium in media]

这里返回的是一个嵌套的列表,格式为

?
1
2
3
4
5
6
7
8
9
10
[
    [   '<link href="path_1" type="text/css" media="medium_type_1" rel="stylesheet" />',
        '<link href="path_2" type="text/css" media="medium_type_1" rel="stylesheet" />'
    ]   #medium_type_1
     
    [   '<link href="path_1" type="text/css" media="medium_type_2" rel="stylesheet" />',
        '<link href="path_2" type="text/css" media="medium_type_2" rel="stylesheet" />'
    ]   #medium_type_2
    ...
]

然后使用chain(*lists),使用*传参,是chain比较常用的技巧。

render()方法的chain调用,也是一样的


最后说下Media使用的流程。

  初始化

?
1
def __init__(self, media=None**kwargs):

   优先使用media参数,其次使用kwargs参数。

    还可以看出这些参数只有这些属性有用

?
1
MEDIA_TYPES = ('css''js')

   并且这些格式必须符合add_js( )和add_css( )的参数data格式。


使用add_js( )和add_css( )添加文件路径。


使用render_js( )和 render_css( ), render( )输出html语句。

    注意 absolute_path(self, path, prefix=None)方法,

    对path有特殊的要求。


获取js和css

?
1
__getitem__(self, name):

使得我们可以通过字典的方式获得。它返回的是一个新的meida实例。

?
1
return Media(**{str(name): getattr(self'_' + name)})


0 0