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

Commitf601c6c

Browse files
Merge pull request#3313 from tomchristie/limit-selects
Limit rendering of relational selects to max 1000 items by default.
2 parents490f0c9 +c271568 commitf601c6c

File tree

10 files changed

+75
-13
lines changed

10 files changed

+75
-13
lines changed

‎docs/api-guide/fields.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Two options are currently used in HTML form generation, `'input_type'` and `'bas
100100
style = {'base_template': 'radio.html'}
101101
}
102102

103-
**Note**: The`style` argument replaces the old-style version 2.x`widget` keyword argument. Because REST framework 3 now uses templated HTML form generation, the`widget` option that was used to support Django built-in widgets can no longer be supported. Version 3.1 is planned to include public API support for customizing HTML form generation.
103+
**Note**: The`style` argument replaces the old-style version 2.x`widget` keyword argument. Because REST framework 3 now uses templated HTML form generation, the`widget` option that was used to support Django built-in widgets can no longer be supported. Version 3.3 is planned to include public API support for customizing HTML form generation.
104104

105105
---
106106

@@ -364,6 +364,8 @@ Used by `ModelSerializer` to automatically generate fields if the corresponding
364364

365365
-`choices` - A list of valid values, or a list of`(key, display_name)` tuples.
366366
-`allow_blank` - If set to`True` then the empty string should be considered a valid value. If set to`False` then the empty string is considered invalid and will raise a validation error. Defaults to`False`.
367+
-`html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to`None`.
368+
-`html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to`"More than {count} items…"`
367369

368370
Both the`allow_blank` and`allow_null` are valid options on`ChoiceField`, although it is highly recommended that you only use one and not both.`allow_blank` should be preferred for textual choices, and`allow_null` should be preferred for numeric or other non-textual choices.
369371

@@ -375,6 +377,8 @@ A field that can accept a set of zero, one or many values, chosen from a limited
375377

376378
-`choices` - A list of valid values, or a list of`(key, display_name)` tuples.
377379
-`allow_blank` - If set to`True` then the empty string should be considered a valid value. If set to`False` then the empty string is considered invalid and will raise a validation error. Defaults to`False`.
380+
-`html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to`None`.
381+
-`html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to`"More than {count} items…"`
378382

379383
As with`ChoiceField`, both the`allow_blank` and`allow_null` options are valid, although it is highly recommended that you only use one and not both.`allow_blank` should be preferred for textual choices, and`allow_null` should be preferred for numeric or other non-textual choices.
380384

‎docs/api-guide/relations.md‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Relational fields are used to represent model relationships. They can be applie
1616

1717
---
1818

19-
####Inspectingautomatically generatedrelationships.
19+
####Inspecting relationships.
2020

2121
When using the`ModelSerializer` class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.
2222

@@ -442,6 +442,25 @@ To provide customized representations for such inputs, override `display_value()
442442
def display_value(self, instance):
443443
return 'Track: %s' % (instance.title)
444444

445+
##Select field cutoffs
446+
447+
When rendered in the browsable API relational fields will default to only displaying a maximum of 1000 selectable items. If more items are present then a disabled option with "More than 1000 items…" will be displayed.
448+
449+
This behavior is intended to prevent a template from being unable to render in an acceptable timespan due to a very large number of relationships being displayed.
450+
451+
There are two keyword arguments you can use to control this behavior:
452+
453+
-`html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to`None` to disable any limiting. Defaults to`1000`.
454+
-`html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to`"More than {count} items…"`
455+
456+
In cases where the cutoff is being enforced you may want to instead use a plain input field in the HTML form. You can do so using the`style` keyword argument. For example:
457+
458+
assigned_to = serializers.SlugRelatedField(
459+
queryset=User.objects.all(),
460+
slug field='username',
461+
style={'base_template': 'input.html'}
462+
)
463+
445464
##Reverse relations
446465

447466
Note that reverse relationships are not automatically included by the`ModelSerializer` and`HyperlinkedModelSerializer` classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:

‎rest_framework/fields.py‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def flatten_choices_dict(choices):
156156
returnret
157157

158158

159-
defiter_options(grouped_choices):
159+
defiter_options(grouped_choices,cutoff=None,cutoff_text=None):
160160
"""
161161
Helper function for options and option groups in templates.
162162
"""
@@ -175,18 +175,32 @@ class Option(object):
175175
start_option_group=False
176176
end_option_group=False
177177

178-
def__init__(self,value,display_text):
178+
def__init__(self,value,display_text,disabled=False):
179179
self.value=value
180180
self.display_text=display_text
181+
self.disabled=disabled
182+
183+
count=0
181184

182185
forkey,valueingrouped_choices.items():
186+
ifcutoffandcount>=cutoff:
187+
break
188+
183189
ifisinstance(value,dict):
184190
yieldStartOptionGroup(label=key)
185191
forsub_key,sub_valueinvalue.items():
192+
ifcutoffandcount>=cutoff:
193+
break
186194
yieldOption(value=sub_key,display_text=sub_value)
195+
count+=1
187196
yieldEndOptionGroup()
188197
else:
189198
yieldOption(value=key,display_text=value)
199+
count+=1
200+
201+
ifcutoffandcount>=cutoffandcutoff_text:
202+
cutoff_text=cutoff_text.format(count=cutoff)
203+
yieldOption(value='n/a',display_text=cutoff_text,disabled=True)
190204

191205

192206
classCreateOnlyDefault(object):
@@ -1188,10 +1202,14 @@ class ChoiceField(Field):
11881202
default_error_messages= {
11891203
'invalid_choice':_('"{input}" is not a valid choice.')
11901204
}
1205+
html_cutoff=None
1206+
html_cutoff_text=_('More than {count} items...')
11911207

11921208
def__init__(self,choices,**kwargs):
11931209
self.grouped_choices=to_choices_dict(choices)
11941210
self.choices=flatten_choices_dict(self.grouped_choices)
1211+
self.html_cutoff=kwargs.pop('html_cutoff',self.html_cutoff)
1212+
self.html_cutoff_text=kwargs.pop('html_cutoff_text',self.html_cutoff_text)
11951213

11961214
# Map the string representation of choices to the underlying value.
11971215
# Allows us to deal with eg. integer choices while supporting either
@@ -1222,7 +1240,11 @@ def iter_options(self):
12221240
"""
12231241
Helper method for use with templates rendering select widgets.
12241242
"""
1225-
returniter_options(self.grouped_choices)
1243+
returniter_options(
1244+
self.grouped_choices,
1245+
cutoff=self.html_cutoff,
1246+
cutoff_text=self.html_cutoff_text
1247+
)
12261248

12271249

12281250
classMultipleChoiceField(ChoiceField):

‎rest_framework/relations.py‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@ def __init__(self, pk):
5454

5555
classRelatedField(Field):
5656
queryset=None
57+
html_cutoff=1000
58+
html_cutoff_text=_('More than {count} items...')
5759

5860
def__init__(self,**kwargs):
5961
self.queryset=kwargs.pop('queryset',self.queryset)
62+
self.html_cutoff=kwargs.pop('html_cutoff',self.html_cutoff)
63+
self.html_cutoff_text=kwargs.pop('html_cutoff_text',self.html_cutoff_text)
6064
assertself.querysetisnotNoneorkwargs.get('read_only',None), (
6165
'Relational field must provide a `queryset` argument, '
6266
'or set read_only=`True`.'
@@ -158,7 +162,11 @@ def grouped_choices(self):
158162
returnself.choices
159163

160164
defiter_options(self):
161-
returniter_options(self.grouped_choices)
165+
returniter_options(
166+
self.grouped_choices,
167+
cutoff=self.html_cutoff,
168+
cutoff_text=self.html_cutoff_text
169+
)
162170

163171
defdisplay_value(self,instance):
164172
returnsix.text_type(instance)
@@ -415,10 +423,15 @@ class ManyRelatedField(Field):
415423
'not_a_list':_('Expected a list of items but got type "{input_type}".'),
416424
'empty':_('This list may not be empty.')
417425
}
426+
html_cutoff=1000
427+
html_cutoff_text=_('More than {count} items...')
418428

419429
def__init__(self,child_relation=None,*args,**kwargs):
420430
self.child_relation=child_relation
421431
self.allow_empty=kwargs.pop('allow_empty',True)
432+
self.html_cutoff=kwargs.pop('html_cutoff',self.html_cutoff)
433+
self.html_cutoff_text=kwargs.pop('html_cutoff_text',self.html_cutoff_text)
434+
422435
assertchild_relationisnotNone,'`child_relation` is a required argument.'
423436
super(ManyRelatedField,self).__init__(*args,**kwargs)
424437
self.child_relation.bind(field_name='',parent=self)
@@ -469,4 +482,8 @@ def grouped_choices(self):
469482
returnself.choices
470483

471484
defiter_options(self):
472-
returniter_options(self.grouped_choices)
485+
returniter_options(
486+
self.grouped_choices,
487+
cutoff=self.html_cutoff,
488+
cutoff_text=self.html_cutoff_text
489+
)

‎rest_framework/templates/rest_framework/horizontal/select.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
{% elif select.end_option_group %}
1717
</optgroup>
1818
{% else %}
19-
<optionvalue="{{ select.value }}"{%ifselect.value ==field.value%}selected{%endif%}>{{ select.display_text }}</option>
19+
<optionvalue="{{ select.value }}"{%ifselect.value ==field.value%}selected{%endif%}{%ifselect.disabled%}disabled{%endif%}>{{ select.display_text }}</option>
2020
{% endif %}
2121
{% endfor %}
2222
</select>

‎rest_framework/templates/rest_framework/horizontal/select_multiple.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
{% elif select.end_option_group %}
1717
</optgroup>
1818
{% else %}
19-
<optionvalue="{{ select.value }}"{%ifselect.valueinfield.value%}selected{%endif%}>{{ select.display_text }}</option>
19+
<optionvalue="{{ select.value }}"{%ifselect.valueinfield.value%}selected{%endif%}{%ifselect.disabled%}disabled{%endif%}>{{ select.display_text }}</option>
2020
{% endif %}
2121
{% empty %}
2222
<option>{{ no_items }}</option>

‎rest_framework/templates/rest_framework/inline/select.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
{% elif select.end_option_group %}
1616
</optgroup>
1717
{% else %}
18-
<optionvalue="{{ select.value }}"{%ifselect.value ==field.value%}selected{%endif%}>{{ select.display_text }}</option>
18+
<optionvalue="{{ select.value }}"{%ifselect.value ==field.value%}selected{%endif%}{%ifselect.disabled%}disabled{%endif%}>{{ select.display_text }}</option>
1919
{% endif %}
2020
{% endfor %}
2121
</select>

‎rest_framework/templates/rest_framework/inline/select_multiple.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
{% elif select.end_option_group %}
1616
</optgroup>
1717
{% else %}
18-
<optionvalue="{{ select.value }}"{%ifselect.valueinfield.value%}selected{%endif%}>{{ select.display_text }}</option>
18+
<optionvalue="{{ select.value }}"{%ifselect.valueinfield.value%}selected{%endif%}{%ifselect.disabled%}disabled{%endif%}>{{ select.display_text }}</option>
1919
{% endif %}
2020
{% empty %}
2121
<option>{{ no_items }}</option>

‎rest_framework/templates/rest_framework/vertical/select.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
{% elif select.end_option_group %}
1616
</optgroup>
1717
{% else %}
18-
<optionvalue="{{ select.value }}"{%ifselect.value ==field.value%}selected{%endif%}>{{ select.display_text }}</option>
18+
<optionvalue="{{ select.value }}"{%ifselect.value ==field.value%}selected{%endif%}{%ifselect.disabled%}disabled{%endif%}>{{ select.display_text }}</option>
1919
{% endif %}
2020
{% endfor %}
2121
</select>

‎rest_framework/templates/rest_framework/vertical/select_multiple.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
{% elif select.end_option_group %}
1616
</optgroup>
1717
{% else %}
18-
<optionvalue="{{ select.value }}"{%ifselect.valueinfield.value%}selected{%endif%}>{{ select.display_text }}</option>
18+
<optionvalue="{{ select.value }}"{%ifselect.valueinfield.value%}selected{%endif%}{%ifselect.disabled%}disabled{%endif%}>{{ select.display_text }}</option>
1919
{% endif %}
2020
{% empty %}
2121
<option>{{ no_items }}</option>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp