added filter - establishment_id, refactored guide counters
This commit is contained in:
parent
4604c81ede
commit
61d2f6ec46
56
apps/collection/filters.py
Normal file
56
apps/collection/filters.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""Collection app filters."""
|
||||
from django_filters import rest_framework as filters
|
||||
from django.core.validators import EMPTY_VALUES
|
||||
|
||||
from collection import models
|
||||
|
||||
|
||||
class CollectionFilterSet(filters.FilterSet):
|
||||
"""Collection filter set."""
|
||||
establishment_id = filters.NumberFilter(
|
||||
field_name='establishments__id',
|
||||
help_text='Establishment id. Allows to filter list of collections by choosen estblishment. '
|
||||
'Use for Establishment detail\'s sheet to content display within '
|
||||
'"Collections & Guides" tab.'
|
||||
)
|
||||
|
||||
# "ordering" instead of "o" is for backward compatibility
|
||||
ordering = filters.OrderingFilter(
|
||||
# tuple-mapping retains order
|
||||
fields=(
|
||||
('rank', 'rank'),
|
||||
('start', 'start'),
|
||||
),
|
||||
help_text='Ordering by fields - rank, start',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.Collection
|
||||
fields = (
|
||||
'ordering',
|
||||
'establishment_id',
|
||||
)
|
||||
|
||||
|
||||
class GuideFilterSet(filters.FilterSet):
|
||||
"""Guide filter set."""
|
||||
establishment_id = filters.NumberFilter(
|
||||
method='by_establishment_id',
|
||||
help_text='Establishment id. Allows to filter list of guides by choosen establishment. '
|
||||
'Use for Establishment detail\'s sheet to content display within '
|
||||
'"Collections & Guides" tab.'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.Guide
|
||||
fields = (
|
||||
'establishment_id',
|
||||
)
|
||||
|
||||
def by_establishment_id(self, queryset, name, value):
|
||||
"""Filter by establishment id."""
|
||||
if value not in EMPTY_VALUES:
|
||||
return queryset.by_establishment_id(value)
|
||||
return queryset
|
||||
|
|
@ -171,17 +171,26 @@ class GuideQuerySet(models.QuerySet):
|
|||
"""Return QuerySet with related."""
|
||||
return self.select_related('site', )
|
||||
|
||||
def with_extended_related(self):
|
||||
"""Return QuerySet with extended related."""
|
||||
return self.with_base_related().prefetch_related('guideelement_set')
|
||||
|
||||
def by_country_id(self, country_id):
|
||||
"""Return QuerySet filtered by country code."""
|
||||
return self.filter(country_json__id__contains=country_id)
|
||||
|
||||
def annotate_in_restaurant_section(self):
|
||||
"""Annotate flag if GuideElement in RestaurantSectionNode."""
|
||||
restaurant_guides = models.Subquery(
|
||||
self.filter(
|
||||
guideelement__guide_element_type__name='EstablishmentNode',
|
||||
guideelement__parent__guide_element_type__name='RestaurantSectionNode',
|
||||
).values_list('id', flat=True).distinct()
|
||||
)
|
||||
return self.annotate(
|
||||
in_restaurant_section=models.Case(
|
||||
models.When(
|
||||
guideelement__guide_element_type__name='EstablishmentNode',
|
||||
guideelement__parent__guide_element_type__name='RestaurantSectionNode',
|
||||
id__in=restaurant_guides,
|
||||
then=True),
|
||||
default=False,
|
||||
output_field=models.BooleanField(default=False)
|
||||
|
|
@ -190,11 +199,16 @@ class GuideQuerySet(models.QuerySet):
|
|||
|
||||
def annotate_in_shop_section(self):
|
||||
"""Annotate flag if GuideElement in ShopSectionNode."""
|
||||
shop_guides = models.Subquery(
|
||||
self.filter(
|
||||
guideelement__guide_element_type__name='EstablishmentNode',
|
||||
guideelement__parent__guide_element_type__name='ShopSectionNode',
|
||||
).values_list('guideelement__id', flat=True).distinct()
|
||||
)
|
||||
return self.annotate(
|
||||
in_shop_section=models.Case(
|
||||
models.When(
|
||||
guideelement__guide_element_type__name='EstablishmentNode',
|
||||
guideelement__parent__guide_element_type__name='ShopSectionNode',
|
||||
id__in=shop_guides,
|
||||
then=True),
|
||||
default=False,
|
||||
output_field=models.BooleanField(default=False)
|
||||
|
|
@ -205,37 +219,60 @@ class GuideQuerySet(models.QuerySet):
|
|||
"""Return QuerySet with annotated field - restaurant_counter."""
|
||||
return self.annotate_in_restaurant_section().annotate(
|
||||
restaurant_counter=models.Count(
|
||||
'guideelement',
|
||||
'guideelement__establishment',
|
||||
filter=models.Q(in_restaurant_section=True) &
|
||||
models.Q(guideelement__parent_id__isnull=False),
|
||||
distinct=True))
|
||||
models.Q(guideelement__parent_id__isnull=True),
|
||||
distinct=True
|
||||
)
|
||||
)
|
||||
|
||||
def annotate_shop_counter(self):
|
||||
"""Return QuerySet with annotated field - shop_counter."""
|
||||
return self.annotate_in_shop_section().annotate(
|
||||
shop_counter=models.Count(
|
||||
'guideelement',
|
||||
'guideelement__establishment',
|
||||
filter=models.Q(in_shop_section=True) &
|
||||
models.Q(guideelement__parent_id__isnull=False),
|
||||
distinct=True))
|
||||
models.Q(guideelement__parent_id__isnull=True),
|
||||
distinct=True
|
||||
)
|
||||
)
|
||||
|
||||
def annotate_wine_counter(self):
|
||||
"""Return QuerySet with annotated field - shop_counter."""
|
||||
return self.annotate_in_restaurant_section().annotate(
|
||||
wine_counter=models.Count(
|
||||
'guideelement',
|
||||
'guideelement__product',
|
||||
filter=models.Q(guideelement__guide_element_type__name='WineNode') &
|
||||
models.Q(guideelement__parent_id__isnull=False),
|
||||
distinct=True))
|
||||
distinct=True
|
||||
)
|
||||
)
|
||||
|
||||
def annotate_present_objects_counter(self):
|
||||
"""Return QuerySet with annotated field - present_objects_counter."""
|
||||
return self.annotate_in_restaurant_section().annotate(
|
||||
present_objects_counter=models.Count(
|
||||
'guideelement',
|
||||
filter=models.Q(guideelement__guide_element_type__name__in=['EstablishmentNode', 'WineNode']) &
|
||||
models.Q(guideelement__parent_id__isnull=False),
|
||||
distinct=True))
|
||||
return (
|
||||
self.annotate_restaurant_counter()
|
||||
.annotate_shop_counter()
|
||||
.annotate_wine_counter()
|
||||
.annotate(
|
||||
present_objects_counter=(
|
||||
models.F('restaurant_counter') +
|
||||
models.F('shop_counter') +
|
||||
models.F('wine_counter')
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def annotate_counters(self):
|
||||
return (
|
||||
self.annotate_restaurant_counter()
|
||||
.annotate_shop_counter()
|
||||
.annotate_wine_counter()
|
||||
.annotate_present_objects_counter()
|
||||
)
|
||||
|
||||
def by_establishment_id(self, establishment_id: int):
|
||||
return self.filter(guideelement__establishment=establishment_id).distinct()
|
||||
|
||||
|
||||
class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ class GuideBaseSerializer(serializers.ModelSerializer):
|
|||
restaurant_counter = serializers.IntegerField(read_only=True)
|
||||
shop_counter = serializers.IntegerField(read_only=True)
|
||||
wine_counter = serializers.IntegerField(read_only=True)
|
||||
present_objects_counter = serializers.IntegerField(read_only=True)
|
||||
count_objects_during_init = serializers.IntegerField(read_only=True,
|
||||
source='count_related_objects')
|
||||
|
||||
|
|
@ -131,6 +132,7 @@ class GuideBaseSerializer(serializers.ModelSerializer):
|
|||
'restaurant_counter',
|
||||
'shop_counter',
|
||||
'wine_counter',
|
||||
'present_objects_counter',
|
||||
'count_objects_during_init',
|
||||
]
|
||||
extra_kwargs = {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import generics
|
||||
from rest_framework import mixins, permissions, viewsets
|
||||
from rest_framework import status
|
||||
from rest_framework.filters import OrderingFilter
|
||||
from rest_framework.response import Response
|
||||
|
||||
from collection import models, serializers
|
||||
from collection import models, serializers, filters
|
||||
from collection import tasks
|
||||
from utils.views import BindObjectMixin
|
||||
|
||||
|
|
@ -34,12 +32,7 @@ class GuideBaseView(generics.GenericAPIView):
|
|||
|
||||
def get_queryset(self):
|
||||
"""Overridden get_queryset method."""
|
||||
return models.Guide.objects.with_base_related() \
|
||||
.annotate_restaurant_counter() \
|
||||
.annotate_shop_counter() \
|
||||
.annotate_wine_counter() \
|
||||
.annotate_present_objects_counter() \
|
||||
.distinct()
|
||||
return models.Guide.objects.with_extended_related().annotate_counters()
|
||||
|
||||
|
||||
class GuideFilterBaseView(generics.GenericAPIView):
|
||||
|
|
@ -72,17 +65,14 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
|
|||
mixins.RetrieveModelMixin,
|
||||
BindObjectMixin,
|
||||
CollectionViewSet):
|
||||
"""ViewSet for Collection model for BackOffice users."""
|
||||
"""ViewSet for Collections list for BackOffice users and Collection create."""
|
||||
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
queryset = models.Collection.objects.with_base_related()
|
||||
filter_backends = [DjangoFilterBackend, OrderingFilter]
|
||||
queryset = models.Collection.objects.with_base_related().order_by('-start')
|
||||
filter_class = filters.CollectionFilterSet
|
||||
serializer_class = serializers.CollectionBackOfficeSerializer
|
||||
bind_object_serializer_class = serializers.CollectionBindObjectSerializer
|
||||
|
||||
ordering_fields = ('rank', 'start')
|
||||
ordering = ('-start', )
|
||||
|
||||
def perform_binding(self, serializer):
|
||||
data = serializer.validated_data
|
||||
collection = data.pop('collection')
|
||||
|
|
@ -106,7 +96,8 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
|
|||
|
||||
class GuideListCreateView(GuideBaseView,
|
||||
generics.ListCreateAPIView):
|
||||
"""View for Guide model for BackOffice users."""
|
||||
"""View for Guides list for BackOffice users and Guide create."""
|
||||
filter_class = filters.GuideFilterSet
|
||||
|
||||
|
||||
class GuideFilterCreateView(GuideFilterBaseView,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
"""Establishment app filters."""
|
||||
from django.core.validators import EMPTY_VALUES
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django_filters import rest_framework as filters, Filter
|
||||
from django_filters.fields import Lookup
|
||||
from django_filters import rest_framework as filters
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from establishment import models
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ urlpatterns = [
|
|||
name='create-comment'),
|
||||
path('slug/<slug:slug>/comments/<int:comment_id>/', views.EstablishmentCommentRUDView.as_view(),
|
||||
name='rud-comment'),
|
||||
path('slug/<slug:slug>/favorites/', views.EstablishmentFavoritesCreateDestroyView.as_view(),
|
||||
path('slug/<slug:slug>/collections/', views.EstablishmentFavoritesCreateDestroyView.as_view(),
|
||||
name='create-destroy-favorites'),
|
||||
|
||||
# similar establishments by type/subtype
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user