我们可以从键列表中初始化一个新的dict实例:
>>> dict.fromkeys(['spam', 'spam', 'potato'])
{'potato': None, 'spam': None}
一个querydict 是一个字典,所以这应该有效,对吗?
>>> QueryDict.fromkeys(['spam', 'spam', 'potato'])
TypeError: __init__() takes at least 2 arguments (1 given)
当然,我可以做一些像QueryDict('spam&spam&potato')
这样的跛脚,但我的问题是:.fromkeys
方法可以使用,还是完全破坏?
答案 0 :(得分:1)
问题还取决于Django版本。您使用需要QueryDict位置参数query_string
的Django 1.7.x或更早版本。它在Django 1.8中修复,此参数是可选的。
第二个问题是QueryDict
默认情况下会创建一个不可变的实例,并且无法通过mutable=True
传递fromkeys
。密钥不能添加到immutable中,并且该方法在Django 1.8中也会失败。
可以通过这种方式修复:
from django.http.request import QueryDict
class MyQueryDict(QueryDict):
@classmethod
def fromkeys(cls, seq, value='', encoding=None):
result = cls('', mutable=True, encoding=encoding)
for key in seq:
result.appendlist(key, value) # or result.update(key, value)
return result
实现更复杂以反映重复键。默认值是空字符串,因为通过'potato=None&spam=None&spam=None'
方法将其转换为字符串“无”,如urlencode()
一样没有意义。默认结果QueryDict应与QueryDict('potato&spam&spam')
相同。
提出的解决方案非常奇怪,raise NotImplemented()
将是一个更直接的“实现”。 (编辑:我不希望任何更多有用的东西被Django代码库接受)但是我必须同意你,这是一个神秘消息的错误。未实现的功能通常没有记录,如果它们不需要警告说明,因为它们可以被发现很多。
其他解决方案是仅修改__init__
:
class MyQueryDict(QueryDict):
def __init__(self, query_string=None, mutable=True, encoding=None):
super(MyQueryDict, self).__init__(query_string=query_string,
mutable=mutable,
encoding=encoding)
因为不可变的QueryDict实例经常是不切实际的,甚至Django内部使用的一半都是可变的QueryDict实例。
答案 1 :(得分:1)
tl; dr QueryDict.fromkeys
将开始在Django 1.11版本中工作。
在PyCon 2016上,我有机会与一些核心Django开发人员交谈,我们同意继承的方法被破坏并违反了Liskov substitution principle。在其中一个sprints我能够抓住这个痒并修补QueryDict类。
以下是相关的commit和issue,此修补程序现已合并为主文件already in the docs。我使用了类似于hynekcer的第一个提案的实现。
答案 2 :(得分:0)
虽然QueryDict
是一个字典,但主要问题是默认情况下它是一个不可变的字典,此外你还没有得到一个非常好的错误信息(我实际上是这样的使用Django 1.8+并获得更清晰的消息'此QueryDict实例是不可变的')。
那就是说,如果你要创建自己的QueryDict
实例,你可以声明它是可变的:
mutable_query_dict = QueryDict(mutable=True)
# Calling fromkeys directly also throws an 'instance is immutable' error, so it looks like a subtle bug
#! mutable_query_dict.fromkeys(['spam', 'spam', 'potato'])
# But you can always use the update() method like this
mutable_query_dict.update(dict.fromkeys(['spam', 'spam', 'potato']))
如果你有一个预先存在的QueryDict
,那么你可以创建一个它的副本,它会自动变为可变:
regular_query_dict = QueryDict()
# Calling fromkeys() or update() throws an immutable error
#! regular_query_dict.fromkeys(['spam', 'spam', 'potato'])
#! regular_query_dict.update(dict.fromkeys(['spam', 'spam', 'potato']))
# Create a copy of the regular QueryDict to make it mutable
copy_of_regular_query_dict = regular_query_dict.copy()
# Calling fromkeys directly also throws an 'instance is immutable' error, so it looks like a subtle bug
#! copy_of_regular_query_dict.fromkeys(['spam', 'spam', 'potato'])
# But you can always use the update() method like this
copy_of_regular_query_dict.update(dict.fromkeys(['spam', 'spam','potato']))
总之,在fromkeys()
上调用QueryDict
时,它确实存在一个非常微妙的错误。但是你可以使用update()
方法克服它,并且还意识到必须使QueryDict
变为可变。