dajngo.forms.widget-Media

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组成的列表。


通过调用方法的形式,

getattr(self, 'add_' + name),
getattr(self, 'render_' + name)

可以看到都是由

MEDIA_TYPES = ('css', 'js')

来命名的。


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

首先来看render_css(), 

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])


看嵌套列表表达式

[[
            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]

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

[
    [   '<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使用的流程。

  初始化

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

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

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

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

__getitem__(self, name):

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

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



你可能感兴趣的:(django,form,widget)