Skip to content

Commit 07ea4b8

Browse files
Add ModelSelect2Mixin.result_from_instance method (#272)
Enable users to easily override the result JSON per widget without implementing a separate view. --------- Co-authored-by: Johannes Maron <[email protected]>
1 parent 06a437d commit 07ea4b8

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

django_select2/forms.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,28 @@ def label_from_instance(obj):
554554
"""
555555
return str(obj)
556556

557+
def result_from_instance(self, obj, request):
558+
"""
559+
Return a dictionary representing the object.
560+
561+
Can be overridden to change the result returned by
562+
:class:`.AutoResponseView` for each object.
563+
564+
The request passed in will correspond to the request sent to the
565+
:class:`.AutoResponseView` by the widget.
566+
567+
Example usage::
568+
569+
class MyWidget(ModelSelect2Widget):
570+
def result_from_instance(obj, request):
571+
return {
572+
'id': obj.pk,
573+
'text': self.label_from_instance(obj),
574+
'extra_data': obj.extra_data,
575+
}
576+
"""
577+
return {"id": obj.pk, "text": self.label_from_instance(obj)}
578+
557579

558580
class ModelSelect2Widget(ModelSelect2Mixin, HeavySelect2Widget):
559581
"""

django_select2/views.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def get(self, request, *args, **kwargs):
2121
"""
2222
Return a :class:`.django.http.JsonResponse`.
2323
24+
Each result will be rendered by the widget's
25+
:func:`django_select2.forms.ModelSelect2Mixin.result_from_instance` method.
26+
2427
Example::
2528
2629
{
@@ -41,7 +44,7 @@ def get(self, request, *args, **kwargs):
4144
return JsonResponse(
4245
{
4346
"results": [
44-
{"text": self.widget.label_from_instance(obj), "id": obj.pk}
47+
self.widget.result_from_instance(obj, request)
4548
for obj in context["object_list"]
4649
],
4750
"more": context["page_obj"].has_next(),

tests/test_forms.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,15 @@ def test_get_queryset(self):
438438
widget.queryset = Genre.objects.all()
439439
assert isinstance(widget.get_queryset(), QuerySet)
440440

441+
def test_result_from_instance_ModelSelect2Widget(self, genres):
442+
widget = ModelSelect2Widget()
443+
widget.model = Genre
444+
genre = Genre.objects.first()
445+
assert widget.result_from_instance(genre, request=None) == {
446+
"id": genre.pk,
447+
"text": str(genre),
448+
}
449+
441450
def test_tag_attrs_Select2Widget(self):
442451
widget = Select2Widget()
443452
output = widget.render("name", "value")

tests/test_views.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
from django_select2.cache import cache
66
from django_select2.forms import ModelSelect2Widget
7-
from tests.testapp.forms import AlbumModelSelect2WidgetForm, ArtistCustomTitleWidget
7+
from tests.testapp.forms import (
8+
AlbumModelSelect2WidgetForm,
9+
ArtistCustomTitleWidget,
10+
CityForm,
11+
)
812
from tests.testapp.models import Genre
913

1014
try:
@@ -84,6 +88,23 @@ def test_label_from_instance(self, artists, client):
8488
"results"
8589
]
8690

91+
def test_result_from_instance(self, cities, client):
92+
url = reverse("django_select2:auto-json")
93+
94+
form = CityForm()
95+
assert form.as_p()
96+
field_id = form.fields["city"].widget.field_id
97+
city = cities[0]
98+
response = client.get(url, {"field_id": field_id, "term": city.name})
99+
assert response.status_code == 200
100+
data = json.loads(response.content.decode("utf-8"))
101+
assert data["results"]
102+
assert {
103+
"id": city.pk,
104+
"text": smart_str(city),
105+
"country": smart_str(city.country),
106+
} in data["results"]
107+
87108
def test_url_check(self, client, artists):
88109
artist = artists[0]
89110
form = AlbumModelSelect2WidgetForm()

tests/testapp/forms.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,17 @@ class Meta:
232232
model = models.Groupie
233233
fields = "__all__"
234234
widgets = {"obsession": ArtistCustomTitleWidget}
235+
236+
237+
class CityModelSelect2Widget(ModelSelect2Widget):
238+
model = City
239+
search_fields = ["name"]
240+
241+
def result_from_instance(self, obj, request):
242+
return {"id": obj.pk, "text": obj.name, "country": str(obj.country)}
243+
244+
245+
class CityForm(forms.Form):
246+
city = forms.ModelChoiceField(
247+
queryset=City.objects.all(), widget=CityModelSelect2Widget(), required=False
248+
)

0 commit comments

Comments
 (0)