为Djang创建保序多值dict

2024-10-04 05:19:58 发布

您现在位置:Python中文网/ 问答频道 /正文

尝试创建交叉兼容的保序QueryDict子类时:

from collections import OrderedDict

from django.http import QueryDict
from django.conf import settings

settings.configure()

class OrderedQueryDict(QueryDict, OrderedDict):
    pass

querystring = 'z=33&x=11'
print(QueryDict(querystring).urlencode())
print(OrderedQueryDict(querystring).urlencode())

Python3.x上的输出(正确和预期的结果):

z=33&x=11  # or maybe x=11,z=33 on Python<=3.5
z=33&x=11

Python 2.7上的输出(此查询字符串已损坏):

x=11&z=33
z=3&z=3&x=1&x=1

为什么这个想法适用于python3而不适用于python2?

Django v1.11.20版。你知道吗


Tags: djangofromimporthttpsettings子类交叉collections
1条回答
网友
1楼 · 发布于 2024-10-04 05:19:58

TLDR:重新实现lists

class OrderedQueryDict(QueryDict, OrderedDict):
    def lists(self):
        """Returns a list of (key, list) pairs."""
        return [(key, self.getlist(key)) for key in self]

对于完整的功能,iterlists也应该重新实现。你知道吗


问题是Django的MultiValueDict覆盖了__getitem__只检索最后一个值,而getlist检索所有值。这隐式地依赖于不使用重写方法的底层映射的其他方法。例如,它依赖于super().iteritems能够检索值列表:

>>> from django.utils.datastructures import MultiValueDict
>>> d = MultiValueDict({"k": ["v1", "v2"]})
>>> d.items()
[('k', 'v2')]
>>> super(MultiValueDict, d).items()
[('k', ['v1', 'v2'])]

original code使用six覆盖python2和python3。这就是Python 2执行的内容:

def lists(self):
    return list(self.iterlists())

def iterlists(self):
    """Yields (key, list) pairs."""
    return super(MultiValueDict, self).iteritems()

在Python 2中,OrderedDict是用纯Python实现的,并依赖self[key],即__getitem__来检索值:

def iteritems(self):
    'od.iteritems -> an iterator over the (key, value) pairs in od'
    for k in self:
        yield (k, self[k])

因此,它从MRO获取被重写的__getitem__,并且只返回单个值,而不是整个列表。你知道吗

这个问题在大多数python3.5+的构建中都被回避了,因为OrderedDict通常有一个C实现可用,意外地屏蔽了它的方法,使其不使用重写的方法。你知道吗

collections.OrderedDict is now implemented in C, which makes it 4 to 100 times faster.[What's new in Python 3.5]

相关问题 更多 >