Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8f6d7f4

Browse files
Merge pull request#2451 from tomchristie/dict-field
Added DictField and support for HStoreField.
2 parentsb07d931 +35f6a82 commit8f6d7f4

File tree

5 files changed

+139
-5
lines changed

5 files changed

+139
-5
lines changed

‎docs/api-guide/fields.md‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ A field class that validates a list of objects.
380380

381381
**Signature**:`ListField(child)`
382382

383-
-`child` - A field instance that should be used for validating the objects in the list.
383+
-`child` - A field instance that should be used for validating the objects in the list. If this argument is not provided then objects in the list will not be validated.
384384

385385
For example, to validate a list of integers you might use something like the following:
386386

@@ -395,6 +395,23 @@ The `ListField` class also supports a declarative style that allows you to write
395395

396396
We can now reuse our custom`StringListField` class throughout our application, without having to provide a`child` argument to it.
397397

398+
##DictField
399+
400+
A field class that validates a dictionary of objects. The keys in`DictField` are always assumed to be string values.
401+
402+
**Signature**:`DictField(child)`
403+
404+
-`child` - A field instance that should be used for validating the values in the dictionary. If this argument is not provided then values in the mapping will not be validated.
405+
406+
For example, to create a field that validates a mapping of strings to strings, you would write something like this:
407+
408+
document = DictField(child=CharField())
409+
410+
You can also use the declarative style, as with`ListField`. For example:
411+
412+
class DocumentField(DictField):
413+
child = CharField()
414+
398415
---
399416

400417
#Miscellaneous fields

‎rest_framework/compat.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ def total_seconds(timedelta):
5858
fromdjango.httpimportHttpResponseasHttpResponseBase
5959

6060

61+
# contrib.postgres only supported from 1.8 onwards.
62+
try:
63+
fromdjango.contrib.postgresimportfieldsaspostgres_fields
64+
exceptImportError:
65+
postgres_fields=None
66+
67+
6168
# request only provides `resolver_match` from 1.5 onwards.
6269
defget_resolver_match(request):
6370
try:

‎rest_framework/fields.py‎

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,16 +1132,28 @@ def to_internal_value(self, data):
11321132

11331133
# Composite field types...
11341134

1135+
class_UnvalidatedField(Field):
1136+
def__init__(self,*args,**kwargs):
1137+
super(_UnvalidatedField,self).__init__(*args,**kwargs)
1138+
self.allow_blank=True
1139+
self.allow_null=True
1140+
1141+
defto_internal_value(self,data):
1142+
returndata
1143+
1144+
defto_representation(self,value):
1145+
returnvalue
1146+
1147+
11351148
classListField(Field):
1136-
child=None
1149+
child=_UnvalidatedField()
11371150
initial= []
11381151
default_error_messages= {
11391152
'not_a_list':_('Expected a list of items but got type `{input_type}`')
11401153
}
11411154

11421155
def__init__(self,*args,**kwargs):
11431156
self.child=kwargs.pop('child',copy.deepcopy(self.child))
1144-
assertself.childisnotNone,'`child` is a required argument.'
11451157
assertnotinspect.isclass(self.child),'`child` has not been instantiated.'
11461158
super(ListField,self).__init__(*args,**kwargs)
11471159
self.child.bind(field_name='',parent=self)
@@ -1170,6 +1182,49 @@ def to_representation(self, data):
11701182
return [self.child.to_representation(item)foritemindata]
11711183

11721184

1185+
classDictField(Field):
1186+
child=_UnvalidatedField()
1187+
initial= []
1188+
default_error_messages= {
1189+
'not_a_dict':_('Expected a dictionary of items but got type `{input_type}`')
1190+
}
1191+
1192+
def__init__(self,*args,**kwargs):
1193+
self.child=kwargs.pop('child',copy.deepcopy(self.child))
1194+
assertnotinspect.isclass(self.child),'`child` has not been instantiated.'
1195+
super(DictField,self).__init__(*args,**kwargs)
1196+
self.child.bind(field_name='',parent=self)
1197+
1198+
defget_value(self,dictionary):
1199+
# We override the default field access in order to support
1200+
# lists in HTML forms.
1201+
ifhtml.is_html_input(dictionary):
1202+
returnhtml.parse_html_list(dictionary,prefix=self.field_name)
1203+
returndictionary.get(self.field_name,empty)
1204+
1205+
defto_internal_value(self,data):
1206+
"""
1207+
Dicts of native values <- Dicts of primitive datatypes.
1208+
"""
1209+
ifhtml.is_html_input(data):
1210+
data=html.parse_html_dict(data)
1211+
ifnotisinstance(data,dict):
1212+
self.fail('not_a_dict',input_type=type(data).__name__)
1213+
returndict([
1214+
(six.text_type(key),self.child.run_validation(value))
1215+
forkey,valueindata.items()
1216+
])
1217+
1218+
defto_representation(self,value):
1219+
"""
1220+
List of object instances -> List of dicts of primitive datatypes.
1221+
"""
1222+
returndict([
1223+
(six.text_type(key),self.child.to_representation(val))
1224+
forkey,valinvalue.items()
1225+
])
1226+
1227+
11731228
# Miscellaneous field types...
11741229

11751230
classReadOnlyField(Field):

‎rest_framework/serializers.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
fromdjango.dbimportmodels
1515
fromdjango.db.models.fieldsimportFieldDoesNotExist,FieldasDjangoField
1616
fromdjango.utils.translationimportugettext_lazyas_
17-
fromrest_framework.compatimportunicode_to_repr
17+
fromrest_framework.compatimportpostgres_fields,unicode_to_repr
1818
fromrest_framework.utilsimportmodel_meta
1919
fromrest_framework.utils.field_mappingimport (
2020
get_url_kwargs,get_field_kwargs,
@@ -1137,6 +1137,12 @@ class Meta:
11371137
ifhasattr(models,'UUIDField'):
11381138
ModelSerializer._field_mapping[models.UUIDField]=UUIDField
11391139

1140+
ifpostgres_fields:
1141+
classCharMappingField(DictField):
1142+
child=CharField()
1143+
1144+
ModelSerializer._field_mapping[postgres_fields.HStoreField]=CharMappingField
1145+
11401146

11411147
classHyperlinkedModelSerializer(ModelSerializer):
11421148
"""

‎tests/test_fields.py‎

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ class TestValidImageField(FieldValues):
10471047

10481048
classTestListField(FieldValues):
10491049
"""
1050-
Values for `ListField`.
1050+
Values for `ListField` with IntegerField as child.
10511051
"""
10521052
valid_inputs= [
10531053
([1,2,3], [1,2,3]),
@@ -1064,6 +1064,55 @@ class TestListField(FieldValues):
10641064
field=serializers.ListField(child=serializers.IntegerField())
10651065

10661066

1067+
classTestUnvalidatedListField(FieldValues):
1068+
"""
1069+
Values for `ListField` with no `child` argument.
1070+
"""
1071+
valid_inputs= [
1072+
([1,'2',True, [4,5,6]], [1,'2',True, [4,5,6]]),
1073+
]
1074+
invalid_inputs= [
1075+
('not a list', ['Expected a list of items but got type `str`']),
1076+
]
1077+
outputs= [
1078+
([1,'2',True, [4,5,6]], [1,'2',True, [4,5,6]]),
1079+
]
1080+
field=serializers.ListField()
1081+
1082+
1083+
classTestDictField(FieldValues):
1084+
"""
1085+
Values for `ListField` with CharField as child.
1086+
"""
1087+
valid_inputs= [
1088+
({'a':1,'b':'2',3:3}, {'a':'1','b':'2','3':'3'}),
1089+
]
1090+
invalid_inputs= [
1091+
({'a':1,'b':None}, ['This field may not be null.']),
1092+
('not a dict', ['Expected a dictionary of items but got type `str`']),
1093+
]
1094+
outputs= [
1095+
({'a':1,'b':'2',3:3}, {'a':'1','b':'2','3':'3'}),
1096+
]
1097+
field=serializers.DictField(child=serializers.CharField())
1098+
1099+
1100+
classTestUnvalidatedDictField(FieldValues):
1101+
"""
1102+
Values for `ListField` with no `child` argument.
1103+
"""
1104+
valid_inputs= [
1105+
({'a':1,'b': [4,5,6],1:123}, {'a':1,'b': [4,5,6],'1':123}),
1106+
]
1107+
invalid_inputs= [
1108+
('not a dict', ['Expected a dictionary of items but got type `str`']),
1109+
]
1110+
outputs= [
1111+
({'a':1,'b': [4,5,6]}, {'a':1,'b': [4,5,6]}),
1112+
]
1113+
field=serializers.DictField()
1114+
1115+
10671116
# Tests for FieldField.
10681117
# ---------------------
10691118

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp