Skip to content

Commit 053b40c

Browse files
committed
Merge branch 'release/1.6.1'
2 parents 0e03828 + 1311472 commit 053b40c

File tree

9 files changed

+115
-42
lines changed

9 files changed

+115
-42
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Change Log
22

3+
## [1.6.1](https://github.com/crucialfelix/django-ajax-selects/tree/1.6.1) (2017-09-09)
4+
[Full Changelog](https://github.com/crucialfelix/django-ajax-selects/compare/1.6.0...1.6.1)
5+
6+
**Fixed bugs:**
7+
8+
- Fix Lookup.get\_objects for inherited models [\#212](https://github.com/crucialfelix/django-ajax-selects/pull/212) ([crucialfelix](https://github.com/crucialfelix))
9+
10+
**Merged pull requests:**
11+
12+
- Use DjangoJSONEncoder - which handles additional django types [\#206](https://github.com/crucialfelix/django-ajax-selects/pull/206) ([mzdeb](https://github.com/mzdeb))
13+
314
## [1.6.0](https://github.com/crucialfelix/django-ajax-selects/tree/1.6.0) (2017-05-17)
415
[Full Changelog](https://github.com/crucialfelix/django-ajax-selects/compare/1.5.2...1.6.0)
516

ajax_select/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""JQuery-Ajax Autocomplete fields for Django Forms."""
2-
__version__ = "1.6.0"
2+
__version__ = "1.6.1"
33
__author__ = "crucialfelix"
44
__contact__ = "[email protected]"
55
__homepage__ = "https://github.com/crucialfelix/django-ajax-selects/"

ajax_select/fields.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
from __future__ import unicode_literals
2+
23
import json
3-
from ajax_select.registry import registry
4+
45
from django import forms
56
from django.conf import settings
67
from django.contrib.contenttypes.models import ContentType
7-
from django.db.models.query import QuerySet
8+
from django.core.serializers.json import DjangoJSONEncoder
9+
from django.db.models import Model
810
from django.forms.utils import flatatt
911
from django.template.defaultfilters import force_escape
1012
from django.template.loader import render_to_string
1113
from django.utils.encoding import force_text
1214
from django.utils.safestring import mark_safe
1315
from django.utils.six import text_type
1416
from django.utils.translation import ugettext as _
17+
18+
from ajax_select.registry import registry
19+
1520
try:
1621
from django.urls import reverse
1722
except ImportError:
@@ -96,7 +101,8 @@ def render(self, name, value, attrs=None):
96101
'func_slug': self.html_id.replace("-", ""),
97102
'add_link': self.add_link,
98103
}
99-
context.update(make_plugin_options(lookup, self.channel, self.plugin_options, initial))
104+
context.update(
105+
make_plugin_options(lookup, self.channel, self.plugin_options, initial))
100106
templates = (
101107
'ajax_select/autocompleteselect_%s.html' % self.channel,
102108
'ajax_select/autocompleteselect.html')
@@ -127,7 +133,8 @@ def __init__(self, channel, *args, **kwargs):
127133
)
128134
widget_kwargs.update(kwargs.pop('widget_options', {}))
129135
kwargs["widget"] = AutoCompleteSelectWidget(**widget_kwargs)
130-
super(AutoCompleteSelectField, self).__init__(max_length=255, *args, **kwargs)
136+
super(AutoCompleteSelectField, self).__init__(
137+
max_length=255, *args, **kwargs)
131138

132139
def clean(self, value):
133140
if value:
@@ -138,7 +145,8 @@ def clean(self, value):
138145
# or your channel is faulty
139146
# out of the scope of this field to do anything more than
140147
# tell you it doesn't exist
141-
raise forms.ValidationError("%s cannot find object: %s" % (lookup, value))
148+
raise forms.ValidationError(
149+
"%s cannot find object: %s" % (lookup, value))
142150
return objs[0]
143151
else:
144152
if self.required:
@@ -194,10 +202,11 @@ def render(self, name, value, attrs=None):
194202

195203
lookup = registry.get(self.channel)
196204

197-
if isinstance(value, QuerySet):
198-
objects = value
205+
values = list(value)
206+
if all([isinstance(v, Model) for v in values]):
207+
objects = values
199208
else:
200-
objects = lookup.get_objects(value)
209+
objects = lookup.get_objects(values)
201210

202211
current_ids = pack_ids([obj.pk for obj in objects])
203212

@@ -217,15 +226,18 @@ def render(self, name, value, attrs=None):
217226
'html_id': self.html_id,
218227
'current': value,
219228
'current_ids': current_ids,
220-
'current_reprs': mark_safe(json.dumps(initial)),
229+
'current_reprs': mark_safe(
230+
json.dumps(initial, cls=DjangoJSONEncoder)
231+
),
221232
'help_text': help_text,
222233
'extra_attrs': mark_safe(flatatt(final_attrs)),
223234
'func_slug': self.html_id.replace("-", ""),
224235
'add_link': self.add_link,
225236
}
226-
context.update(make_plugin_options(lookup, self.channel, self.plugin_options, initial))
237+
context.update(
238+
make_plugin_options(lookup, self.channel, self.plugin_options, initial))
227239
templates = ('ajax_select/autocompleteselectmultiple_%s.html' % self.channel,
228-
'ajax_select/autocompleteselectmultiple.html')
240+
'ajax_select/autocompleteselectmultiple.html')
229241
out = render_to_string(templates, context)
230242
return mark_safe(out)
231243

@@ -269,7 +281,8 @@ def __init__(self, channel, *args, **kwargs):
269281
dh = 'Hold down "Control", or "Command" on a Mac, to select more than one.'
270282
django_default_help = _(dh).translate(settings.LANGUAGE_CODE)
271283
if django_default_help in translated:
272-
cleaned_help = translated.replace(django_default_help, '').strip()
284+
cleaned_help = translated.replace(
285+
django_default_help, '').strip()
273286
# probably will not show up in translations
274287
if cleaned_help:
275288
help_text = cleaned_help
@@ -358,13 +371,15 @@ def render(self, name, value, attrs=None):
358371
'extra_attrs': mark_safe(flatatt(final_attrs)),
359372
'func_slug': self.html_id.replace("-", ""),
360373
}
361-
context.update(make_plugin_options(lookup, self.channel, self.plugin_options, initial))
374+
context.update(
375+
make_plugin_options(lookup, self.channel, self.plugin_options, initial))
362376
templates = ('ajax_select/autocomplete_%s.html' % self.channel,
363377
'ajax_select/autocomplete.html')
364378
return mark_safe(render_to_string(templates, context))
365379

366380

367381
class AutoCompleteField(forms.CharField):
382+
368383
"""
369384
A CharField that uses an AutoCompleteWidget to lookup matching
370385
and stores the result as plain text.
@@ -411,7 +426,8 @@ def _check_can_add(self, user, related_model):
411426
if can_add:
412427
app_label = related_model._meta.app_label
413428
model = related_model._meta.object_name.lower()
414-
self.widget.add_link = reverse('admin:%s_%s_add' % (app_label, model)) + '?_popup=1'
429+
self.widget.add_link = reverse(
430+
'admin:%s_%s_add' % (app_label, model)) + '?_popup=1'
415431

416432

417433
def autoselect_fields_check_can_add(form, model, user):
@@ -441,8 +457,10 @@ def make_plugin_options(lookup, channel_name, widget_plugin_options, initial):
441457
po['html'] = True
442458

443459
return {
444-
'plugin_options': mark_safe(json.dumps(po)),
445-
'data_plugin_options': force_escape(json.dumps(po))
460+
'plugin_options': mark_safe(json.dumps(po, cls=DjangoJSONEncoder)),
461+
'data_plugin_options': force_escape(
462+
json.dumps(po, cls=DjangoJSONEncoder)
463+
)
446464
}
447465

448466

ajax_select/lookup_channel.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,10 @@ def get_objects(self, ids):
9494
Returns:
9595
list: list of Model objects
9696
"""
97+
# Inherited models have a OneToOneField (rather than eg AutoField)
9798
if self.model._meta.pk.rel is not None:
9899
# Use the type of the field being referenced
99-
pk_type = self.model._meta.pk.target_field.to_python
100+
pk_type = self.model._meta.pk.rel.field.to_python
100101
else:
101102
pk_type = self.model._meta.pk.to_python
102103

setup.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,23 @@
99

1010
setup(
1111
name='django-ajax-selects',
12-
version='1.6.0',
12+
version='1.6.1',
1313
description='Edit ForeignKey, ManyToManyField and CharField in Django Admin using jQuery UI AutoComplete.',
1414
author='Chris Sattinger',
1515
author_email='[email protected]',
1616
url='https://github.com/crucialfelix/django-ajax-selects/',
1717
packages=['ajax_select'],
1818
package_data={'ajax_select':
19-
[
20-
'*.py',
21-
'*.txt',
22-
'*.md',
23-
'static/ajax_select/css/*',
24-
'static/ajax_select/images/*',
25-
'static/ajax_select/js/*',
26-
'templates/ajax_select/*.html'
27-
]
28-
},
19+
[
20+
'*.py',
21+
'*.txt',
22+
'*.md',
23+
'static/ajax_select/css/*',
24+
'static/ajax_select/images/*',
25+
'static/ajax_select/js/*',
26+
'templates/ajax_select/*.html'
27+
]
28+
},
2929
include_package_data=True,
3030
zip_safe=False,
3131
license="MIT",

tests/lookups.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
44
Should not be used by other tests.
55
"""
6-
from django.utils.html import escape
76
from django.contrib.auth.models import User
8-
from tests.models import Person, Author
7+
from django.utils.html import escape
8+
99
import ajax_select
1010

11+
from tests.models import Author, Person, PersonWithTitle
12+
1113

1214
@ajax_select.register('person')
1315
class PersonLookup(ajax_select.LookupChannel):
@@ -27,6 +29,18 @@ def format_item_display(self, obj):
2729
return "%s<div><i>%s</i></div>" % (escape(obj.name), escape(obj.email))
2830

2931

32+
@ajax_select.register('person-with-title')
33+
class PersonWithTitleLookup(ajax_select.LookupChannel):
34+
35+
model = PersonWithTitle
36+
37+
def get_query(self, q, request):
38+
return self.model.objects.filter(title__icontains=q)
39+
40+
def get_result(self, obj):
41+
return "{} {}".format(obj.name, obj.title)
42+
43+
3044
@ajax_select.register('user')
3145
class UserLookup(ajax_select.LookupChannel):
3246

tests/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ class Meta:
1111
app_label = 'tests'
1212

1313

14+
class PersonWithTitle(Person):
15+
16+
"""
17+
Testing an inherited model (multi-table)
18+
"""
19+
20+
title = models.CharField(max_length=150)
21+
22+
class Meta:
23+
app_label = 'tests'
24+
25+
1426
class Author(models.Model):
1527

1628
name = models.CharField(max_length=50)

tests/test_lookups.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
11

2-
from django.test import TestCase
32
from django.contrib.auth.models import User
4-
from .lookups import UserLookup
3+
from django.test import TestCase
4+
5+
from tests.lookups import PersonWithTitleLookup, UserLookup
6+
from tests.models import PersonWithTitle
57

68

79
class TestLookups(TestCase):
810

911
def test_get_objects(self):
1012
user1 = User.objects.create(username='user1',
11-
12-
password='password')
13+
14+
password='password')
1315
user2 = User.objects.create(username='user2',
14-
15-
password='password')
16+
17+
password='password')
1618
lookup = UserLookup()
19+
# deliberately asking for them backwards:
1720
users = lookup.get_objects([user2.id, user1.id])
1821
self.assertEqual(len(users), 2)
22+
# to make sure they come back in the order requested
1923
u2, u1 = users
2024
self.assertEqual(u1, user1)
2125
self.assertEqual(u2, user2)
26+
27+
def test_get_objects_inherited_model(self):
28+
"""
29+
Tests that get_objects works with inherited models
30+
"""
31+
one = PersonWithTitle.objects.create(name='one', title='The One')
32+
two = PersonWithTitle.objects.create(name='two', title='The Other')
33+
lookup = PersonWithTitleLookup()
34+
users = lookup.get_objects([one.id, two.id])
35+
self.assertEqual(len(users), 2)
36+
u1, u2 = users
37+
self.assertEqual(u1, one)
38+
self.assertEqual(u2, two)

tox.ini

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ setenv =
1616
PYTHONPATH = {toxinidir}:{toxinidir}/ajax_select:{toxinidir}/tests
1717
commands = django-admin.py test tests
1818
deps =
19-
dj17: Django>=1.7,<1.8
20-
dj18: Django>=1.8,<1.9
21-
dj19: Django>=1.9,<1.10
22-
dj110: Django>=1.10,<1.11
23-
dj111: Django>=1.11,<1.12
19+
dj17: Django>=1.7.11,<1.8
20+
dj18: Django>=1.8.18,<1.9
21+
dj19: Django>=1.9.13,<1.10
22+
dj110: Django>=1.10.8,<1.11
23+
dj111: Django>=1.11.5,<1.12
2424
; djmaster: https://github.com/django/django/zipball/master
2525

2626
[testenv:py27-flake8]

0 commit comments

Comments
 (0)