From 25b478f2272ebbd811786db6da2b7268c6c5d63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Fri, 27 Oct 2017 13:47:12 +0200 Subject: [PATCH] add first subtitle code --- src/c3nav/mapdata/api.py | 45 +++++++++++++++------------ src/c3nav/mapdata/models/locations.py | 16 ++++++++++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/c3nav/mapdata/api.py b/src/c3nav/mapdata/api.py index d9edc767..67531b60 100644 --- a/src/c3nav/mapdata/api.py +++ b/src/c3nav/mapdata/api.py @@ -186,43 +186,44 @@ class LocationGroupViewSet(MapdataViewSet): class LocationViewSet(RetrieveModelMixin, GenericViewSet): """ only accesses locations that have can_search or can_describe set to true. - add ?detailed=1 to show all attributes, add ?group= to filter by group. + add ?detailed=1 to show all attributes, add ?geometry=1 to show geometries, add ?group= to filter by group /{id}/ add ?show_redirect=1 to suppress redirects and show them as JSON. /search/ only accesses locations that have can_search set to true. Add GET Parameter ā€œsā€ to search. """ queryset = LocationSlug.objects.all() lookup_field = 'slug' - def get_queryset(self, detailed=False, subconditions=None, group=None): + def get_queryset(self, search=False, group=None): queryset = super().get_queryset().order_by('id') conditions = [] for model in get_submodels(Location): if group is not None and not hasattr(model, 'groups'): continue - condition = Q(**{model._meta.default_related_name + '__isnull': False}) - if subconditions: - condition &= reduce(operator.or_, (Q(**{model._meta.default_related_name+'__'+name: value}) - for name, value in subconditions.items())) + related_name = model._meta.default_related_name + condition = Q(**{related_name+'__isnull': False}) + if search: + condition &= Q(**{related_name+'__can_search': True}) + else: + condition &= Q(**{related_name+'__can_search': True, related_name+'__can_describe': True}) if group is not None: - condition &= Q(**{model._meta.default_related_name+'__groups': group}) + condition &= Q(**{related_name+'__groups': group}) # noinspection PyUnresolvedReferences - condition &= model.q_for_request(self.request, prefix=model._meta.default_related_name+'__') + condition &= model.q_for_request(self.request, prefix=related_name+'__') conditions.append(condition) queryset = queryset.filter(reduce(operator.or_, conditions)) - if detailed: - base_qs = LocationGroup.objects.all().select_related('category') - for model in get_submodels(SpecificLocation): - queryset = queryset.prefetch_related(Prefetch(model._meta.default_related_name + '__groups', - queryset=base_qs)) + # prefetch locationgroups + base_qs = LocationGroup.objects.all().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 def list(self, request, *args, **kwargs): detailed = 'detailed' in request.GET - - subconditions = {'can_search': True, 'can_describe': True} + geometry = 'geometry' in request.GET group = None if 'group' in request.GET: @@ -233,9 +234,10 @@ class LocationViewSet(RetrieveModelMixin, GenericViewSet): except LocationGroupCategory.DoesNotExist: raise NotFound(detail=_('group not found.')) - queryset = self.get_queryset(detailed=detailed, subconditions=subconditions, group=group) + queryset = self.get_queryset(group=group) - return Response([obj.get_child().serialize(include_type=True, detailed=detailed) for obj in queryset]) + return Response([obj.get_child().serialize(include_type=True, detailed=detailed, geometry=geometry) + for obj in queryset]) def retrieve(self, request, slug=None, *args, **kwargs): result = Location.get_by_slug(slug, self.get_queryset()) @@ -259,19 +261,22 @@ class LocationViewSet(RetrieveModelMixin, GenericViewSet): @list_route(methods=['get']) def search(self, request): detailed = 'detailed' in request.GET + geometry = 'geometry' in request.GET search = request.GET.get('s') - queryset = self.get_queryset(detailed=detailed, subconditions={'can_search': True}) + queryset = self.get_queryset(search=True) if not search: - return Response([obj.get_child().serialize(include_type=True, detailed=detailed) for obj in queryset]) + return Response([obj.get_child().serialize(include_type=True, detailed=detailed, geometry=geometry) + for obj in queryset]) words = search.lower().split(' ')[:10] results = queryset for word in words: results = [r for r in results if (word in r.title.lower() or (r.slug and word in r.slug.lower()))] # todo: rank results - return Response([obj.get_child().serialize(include_type=True, detailed=detailed) for obj in results]) + return Response([obj.get_child().serialize(include_type=True, detailed=detailed, geometry=geometry) + for obj in results]) class SourceViewSet(MapdataViewSet): diff --git a/src/c3nav/mapdata/models/locations.py b/src/c3nav/mapdata/models/locations.py index f9d415a0..18d11ba1 100644 --- a/src/c3nav/mapdata/models/locations.py +++ b/src/c3nav/mapdata/models/locations.py @@ -81,6 +81,7 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model): def _serialize(self, **kwargs): result = super()._serialize(**kwargs) + result['subtitle'] = self.subtitle result['can_search'] = self.can_search result['can_describe'] = self.can_search return result @@ -122,6 +123,10 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model): return self._meta.verbose_name + ' ' + self.slug return super().title + @property + def subtitle(self): + return '' + def get_color(self, instance=None): # dont filter in the query here so prefetch_related works if instance is None: @@ -150,6 +155,17 @@ class SpecificLocation(Location, models.Model): result['groups'] = groups return result + @property + def subtitle(self): + related_name = self.__class__._meta.default_related_name + groups = tuple(self.groups.all()) + if groups: + group = max((group for group in groups if getattr(group.category, 'allow_'+related_name)), + key=lambda group: (group.category.priority, group.priority), default=None) + return group.title + else: + return str(self.__class__._meta.verbose_name) + class LocationGroupCategory(TitledMixin, models.Model): name = models.SlugField(_('Name'), unique=True, max_length=50)