Impooved cacheing to reduce pickling issues

Not not the entire widget gets cached nor the entire queryset.
The query and gets pickeld separately.
This commit is contained in:
Johannes Hoppe 2015-10-01 12:05:45 +02:00
parent dc81c2b3b5
commit 75c8c38e2d
3 changed files with 39 additions and 12 deletions

View file

@ -300,7 +300,25 @@ class ModelSelect2Mixin(object):
defaults.update(kwargs)
super(ModelSelect2Mixin, self).__init__(*args, **defaults)
def filter_queryset(self, term):
def set_to_cache(self):
"""
Add widget's attributes to Djnago's cache.
Split the queryset, to not pickle the result set.
"""
queryset = self.get_queryset()
cache.set(self._get_cache_key(), {
'queryset':
[
queryset.none(),
queryset.query,
],
'cls': self.__class__,
'search_fields': self.search_fields,
'max_results': self.max_results,
})
def filter_queryset(self, term, queryset=None):
"""
Return queryset filtered by search_fields matching the passed term.
@ -309,7 +327,8 @@ class ModelSelect2Mixin(object):
:return: Filtered queryset
:rtype: :class:`.django.db.models.QuerySet`
"""
qs = self.get_queryset()
if not queryset:
queryset = self.get_queryset()
search_fields = self.get_search_fields()
select = Q()
term = term.replace('\t', ' ')
@ -317,7 +336,7 @@ class ModelSelect2Mixin(object):
for t in [t for t in term.split(' ') if not t == '']:
select &= reduce(lambda x, y: x | Q(**{y: t}), search_fields,
Q(**{search_fields.pop(): t}))
return qs.filter(select).distinct()
return queryset.filter(select).distinct()
def get_queryset(self):
"""

View file

@ -52,7 +52,7 @@ class AutoResponseView(BaseListView):
def get_queryset(self):
"""Get queryset from cached widget."""
return self.widget.filter_queryset(self.term)
return self.widget.filter_queryset(self.term, self.queryset)
def get_paginate_by(self, queryset):
"""Paginate response by size of widget's `max_results` parameter."""
@ -76,7 +76,11 @@ class AutoResponseView(BaseListView):
raise Http404('Invalid "field_id".')
else:
cache_key = '%s%s' % (settings.SELECT2_CACHE_PREFIX, key)
widget = cache.get(cache_key)
if widget is None:
widget_dict = cache.get(cache_key)
if widget_dict is None:
raise Http404('field_id not found')
return widget
qs, qs.query = widget_dict.pop('queryset')
self.queryset = qs.all()
widget_dict['queryset'] = self.queryset
widget_cls = widget_dict.pop('cls')
return widget_cls(**widget_dict)

View file

@ -161,13 +161,13 @@ class TestModelSelect2Mixin(TestHeavySelect2Mixin):
assert result.exists()
def test_queryset_kwarg(self):
widget = ModelSelect2Widget(queryset=Genre.objects, search_fields=['title__icontains'])
widget = ModelSelect2Widget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
genre = Genre.objects.last()
result = widget.filter_queryset(genre.title)
assert result.exists()
def test_ajax_view_registration(self, client):
widget = ModelSelect2Widget(queryset=Genre.objects, search_fields=['title__icontains'])
widget = ModelSelect2Widget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
widget.render('name', 'value')
url = reverse('django_select2-json')
genre = Genre.objects.last()
@ -178,16 +178,20 @@ class TestModelSelect2Mixin(TestHeavySelect2Mixin):
assert genre.pk in [result['id'] for result in data['results']]
def test_render(self):
widget = ModelSelect2Widget()
widget = ModelSelect2Widget(queryset=Genre.objects.all())
widget.render('name', 'value')
cached_widget = cache.get(widget._get_cache_key())
assert isinstance(cached_widget, ModelSelect2Widget)
assert cached_widget['max_results'] == widget.max_results
assert cached_widget['search_fields'] == widget.search_fields
qs = widget.get_queryset()
assert isinstance(cached_widget['queryset'][0], qs.__class__)
assert text_type(cached_widget['queryset'][1]) == text_type(qs.query)
class TestHeavySelect2TagWidget(TestHeavySelect2Mixin):
def test_tag_attrs(self):
widget = ModelSelect2TagWidget(queryset=Genre.objects, search_fields=['title__icontains'])
widget = ModelSelect2TagWidget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
output = widget.render('name', 'value')
assert 'data-minimum-input-length="1"' in output
assert 'data-tags="true"' in output