move complicated Location API Queryset into LocationSlug

This commit is contained in:
Laura Klünder 2017-10-31 13:25:42 +01:00
parent aec7935ab0
commit be2a81f806
2 changed files with 36 additions and 30 deletions

View file

@ -1,9 +1,9 @@
import mimetypes import mimetypes
import operator import operator
from functools import reduce, wraps from functools import wraps
from django.core.cache import cache from django.core.cache import cache
from django.db.models import Prefetch, Q from django.db.models import Prefetch
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.cache import get_conditional_response from django.utils.cache import get_conditional_response
@ -223,29 +223,8 @@ class LocationViewSet(RetrieveModelMixin, GenericViewSet):
queryset = LocationSlug.objects.all() queryset = LocationSlug.objects.all()
lookup_field = 'slug' lookup_field = 'slug'
def get_queryset(self, mode=None): def get_queryset(self, can=None):
queryset = super().get_queryset().order_by('id') return LocationSlug.location_qs_for_request(self.request, can=can)
conditions = []
for model in get_submodels(Location):
related_name = model._meta.default_related_name
condition = Q(**{related_name+'__isnull': False})
if mode == 'search':
condition &= Q(**{related_name+'__can_search': True})
elif mode == 'search-describe':
condition &= Q(**{related_name+'__can_search': True}) | Q(**{related_name+'__can_describe': True})
# noinspection PyUnresolvedReferences
condition &= model.q_for_request(self.request, prefix=related_name+'__')
conditions.append(condition)
queryset = queryset.filter(reduce(operator.or_, conditions))
# prefetch locationgroups
base_qs = LocationGroup.qs_for_request(self.request).select_related('category')
for model in get_submodels(SpecificLocation):
queryset = queryset.prefetch_related(Prefetch(model._meta.default_related_name + '__groups',
queryset=base_qs))
return queryset
@simple_api_cache() @simple_api_cache()
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -265,7 +244,7 @@ class LocationViewSet(RetrieveModelMixin, GenericViewSet):
) )
queryset = cache.get(queryset_cache_key, None) queryset = cache.get(queryset_cache_key, None)
if queryset is None or 1: if queryset is None or 1:
queryset = self.get_queryset(mode=('searchable' if searchable else 'searchable-describe')) queryset = self.get_queryset(can=(('search', ) if searchable else ('search', 'describe')))
queryset = tuple(obj.get_child() for obj in queryset) queryset = tuple(obj.get_child() for obj in queryset)
@ -316,7 +295,7 @@ class LocationViewSet(RetrieveModelMixin, GenericViewSet):
@simple_api_cache() @simple_api_cache()
def retrieve(self, request, slug=None, *args, **kwargs): def retrieve(self, request, slug=None, *args, **kwargs):
result = Location.get_by_slug(slug, self.get_queryset()) result = Location.get_by_slug(slug, request)
if result is None: if result is None:
raise NotFound raise NotFound
result = result.get_child() result = result.get_child()

View file

@ -1,9 +1,11 @@
import operator
from collections import OrderedDict from collections import OrderedDict
from contextlib import suppress from contextlib import suppress
from functools import reduce
from django.apps import apps from django.apps import apps
from django.db import models from django.db import models
from django.db.models import Prefetch from django.db.models import Prefetch, Q
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.text import format_lazy from django.utils.text import format_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -67,6 +69,29 @@ class LocationSlug(SerializableMixin, models.Model):
verbose_name_plural = _('Location with Slug') verbose_name_plural = _('Location with Slug')
default_related_name = 'locationslugs' default_related_name = 'locationslugs'
@classmethod
def location_qs_for_request(cls, request, can=None):
queryset = cls.objects.all().order_by('id')
conditions = []
for model in get_submodels(Location):
related_name = model._meta.default_related_name
condition = Q(**{related_name + '__isnull': False})
if can:
condition &= reduce(operator.or_, (Q(**{related_name+'__can_'+s: True}) for s in can))
# noinspection PyUnresolvedReferences
condition &= model.q_for_request(request, prefix=related_name + '__')
conditions.append(condition)
queryset = queryset.filter(reduce(operator.or_, conditions))
# prefetch locationgroups
base_qs = LocationGroup.qs_for_request(request).select_related('category')
for model in get_submodels(SpecificLocation):
queryset = queryset.prefetch_related(Prefetch(model._meta.default_related_name + '__groups',
queryset=base_qs))
return queryset
class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model): class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model):
can_search = models.BooleanField(default=True, verbose_name=_('can be searched')) can_search = models.BooleanField(default=True, verbose_name=_('can be searched'))
@ -103,9 +128,11 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model):
return self.slug return self.slug
@classmethod @classmethod
def get_by_slug(cls, slug, queryset=None): def get_by_slug(cls, slug, request=None, can=None):
if queryset is None: if request is None:
queryset = LocationSlug.objects.all() queryset = LocationSlug.objects.all()
else:
queryset = LocationSlug.location_qs_for_request(request, can)
if ':' in slug: if ':' in slug:
code, pk = slug.split(':', 1) code, pk = slug.split(':', 1)