From d321866dc21b45eb2205930cd4a01098f7f3e132 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Tue, 8 Oct 2019 15:38:35 +0300 Subject: [PATCH 01/25] gm-192: in progress --- apps/account/views/web.py | 3 +- apps/establishment/admin.py | 22 +++-- ...ishmenttag_establishmenttypetagcategory.py | 39 ++++++++ apps/establishment/models.py | 62 +++++++++++- apps/establishment/serializers/back.py | 17 ++++ apps/establishment/serializers/common.py | 64 ++++++++----- apps/establishment/urls/back.py | 6 ++ apps/establishment/urls/web.py | 2 +- apps/establishment/views/back.py | 94 ++++++++++++++++++- apps/establishment/views/web.py | 36 +------ apps/main/admin.py | 16 ---- apps/main/models.py | 1 - .../search_indexes/documents/establishment.py | 23 ++--- apps/tag/__init__.py | 0 apps/tag/admin.py | 12 +++ apps/tag/apps.py | 7 ++ apps/tag/migrations/0001_initial.py | 44 +++++++++ apps/tag/migrations/__init__.py | 0 apps/tag/models.py | 51 ++++++++++ apps/tag/serializers.py | 44 +++++++++ apps/tag/tests.py | 3 + apps/tag/urls.py | 10 ++ apps/tag/views.py | 18 ++++ project/settings/base.py | 1 + project/urls/back.py | 6 +- 25 files changed, 477 insertions(+), 104 deletions(-) create mode 100644 apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py create mode 100644 apps/tag/__init__.py create mode 100644 apps/tag/admin.py create mode 100644 apps/tag/apps.py create mode 100644 apps/tag/migrations/0001_initial.py create mode 100644 apps/tag/migrations/__init__.py create mode 100644 apps/tag/models.py create mode 100644 apps/tag/serializers.py create mode 100644 apps/tag/tests.py create mode 100644 apps/tag/urls.py create mode 100644 apps/tag/views.py diff --git a/apps/account/views/web.py b/apps/account/views/web.py index 897c955e..9f2ebcfd 100644 --- a/apps/account/views/web.py +++ b/apps/account/views/web.py @@ -40,8 +40,7 @@ class PasswordResetConfirmView(JWTGenericViewMixin): queryset = models.User.objects.active() def get_object(self): - """Override get_object method - """ + """Override get_object method""" queryset = self.filter_queryset(self.get_queryset()) uidb64 = self.kwargs.get('uidb64') diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index f95dd5c8..a40475b0 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _ from comment.models import Comment from establishment import models -from main.models import Award, MetaDataContent +from main.models import Award from review import models as review_models @@ -24,11 +24,6 @@ class AwardInline(GenericTabularInline): extra = 0 -class MetaDataContentInline(GenericTabularInline): - model = MetaDataContent - extra = 0 - - class ContactPhoneInline(admin.TabularInline): """Contact phone inline admin.""" model = models.ContactPhone @@ -56,8 +51,7 @@ class EstablishmentAdmin(admin.ModelAdmin): """Establishment admin.""" list_display = ['id', '__str__', 'image_tag', ] inlines = [ - AwardInline, MetaDataContentInline, - ContactPhoneInline, ContactEmailInline, + AwardInline, ContactPhoneInline, ContactEmailInline, ReviewInline, CommentInline] @@ -84,4 +78,14 @@ class MenuAdmin(admin.ModelAdmin): """Get user's short name.""" return obj.category_translated - category_translated.short_description = _('category') \ No newline at end of file + category_translated.short_description = _('category') + + +@admin.register(models.EstablishmentTypeTagCategory) +class EstablishmentTypeTagCategory(admin.ModelAdmin): + """EstablishmentTypeTagCategory admin.""" + + +@admin.register(models.EstablishmentTag) +class EstablishmentTag(admin.ModelAdmin): + """EstablishmentTag admin.""" diff --git a/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py b/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py new file mode 100644 index 00000000..6efaa57a --- /dev/null +++ b/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py @@ -0,0 +1,39 @@ +# Generated by Django 2.2.4 on 2019-10-08 07:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0001_initial'), + ('establishment', '0031_establishment_slug'), + ] + + operations = [ + migrations.CreateModel( + name='EstablishmentTypeTagCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('establishment_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tag_categories', to='establishment.EstablishmentType', verbose_name='establishment type')), + ('tag_category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='est_type_tag_categories', to='tag.TagCategory', verbose_name='tag category')), + ], + options={ + 'verbose_name': 'establishment type tag categories', + 'verbose_name_plural': 'establishment type tag categories', + }, + ), + migrations.CreateModel( + name='EstablishmentTag', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('establishment', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tags', to='establishment.Establishment', verbose_name='establishment')), + ('tag', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tags', to='tag.Tag', verbose_name='tag')), + ], + options={ + 'verbose_name': 'establishment tag', + 'verbose_name_plural': 'establishment tags', + }, + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 5c2a0ff0..9ce4eebc 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -76,11 +76,13 @@ class EstablishmentQuerySet(models.QuerySet): def with_base_related(self): """Return qs with related objects.""" - return self.select_related('address').prefetch_related( - models.Prefetch('tags', - MetaDataContent.objects.select_related( - 'metadata__category')) - ) + return self.select_related('address') + # todo: fix this + # return self.select_related('address').prefetch_related( + # models.Prefetch('tags', + # MetaDataContent.objects.select_related( + # 'metadata__category')) + # ) def with_extended_related(self): return self.select_related('establishment_type').\ @@ -546,3 +548,53 @@ class SocialNetwork(models.Model): def __str__(self): return self.title + + +class EstablishmentTagQuerySet(models.QuerySet): + """Establishment tag QuerySet.""" + + def by_country_code(self, code): + """Return establishment tags by establishment country code.""" + return self.filter(establishment__address__city__country__code=code) + + +class EstablishmentTag(models.Model): + """Establishment tag model.""" + tag = models.ForeignKey('tag.Tag', + on_delete=models.SET_NULL, null=True, + related_name='tags', + verbose_name=_('tag')) + establishment = models.ForeignKey('establishment.Establishment', + on_delete=models.SET_NULL, null=True, + related_name='tags', + verbose_name=_('establishment')) + objects = EstablishmentTagQuerySet.as_manager() + + class Meta: + verbose_name = _('establishment tag') + verbose_name_plural = _('establishment tags') + + +class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): + """EstablishmentTypeTagCategory QuerySet.""" + + def by_country_code(self, code): + """Return establishment tags by country code""" + return self.filter(tag_category__country__code=code) + + +class EstablishmentTypeTagCategory(models.Model): + """Tag categories based on establishment type.""" + establishment_type = models.ForeignKey(EstablishmentType, + on_delete=models.SET_NULL, null=True, + related_name='tag_categories', + verbose_name=_('establishment type')) + tag_category = models.ForeignKey('tag.TagCategory', + on_delete=models.SET_NULL, null=True, + related_name='est_type_tag_categories', + verbose_name=_('tag category')) + objects = EstablishmentTypeTagCategoryQuerySet.as_manager() + + class Meta: + verbose_name = _('establishment type tag categories') + verbose_name_plural = _('establishment type tag categories') diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index d0c70b2f..b15ff51f 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,4 +1,5 @@ from rest_framework import serializers +from tag.serializers import TagBaseSerializer from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, @@ -6,6 +7,7 @@ from establishment.serializers import ( EstablishmentTypeSerializer) from utils.decorators import with_base_attributes +from utils.serializers import TranslatedField from main.models import Currency @@ -74,6 +76,21 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer): ] +class EstablishmentTagCategoryListSerializer(serializers.ModelSerializer): + """Serializer for intermediate model EstablishmentTypeTagCategories.""" + label_translated = TranslatedField(source='tag_category.label_translated') + tags = TagBaseSerializer(source='tag_category.tags', many=True) + + class Meta: + """Meta class.""" + model = models.EstablishmentTypeTagCategory + fields = [ + 'id', + 'label_translated', + 'tags', + ] + + class SocialNetworkSerializers(serializers.ModelSerializer): """Social network serializers.""" class Meta: diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index f09c8200..6c12360b 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -6,8 +6,8 @@ from comment.serializers import common as comment_serializers from establishment import models from favorites.models import Favorites from location.serializers import AddressBaseSerializer -from main.models import MetaDataContent -from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer +from main.serializers import AwardSerializer, CurrencySerializer +from tag import models as tag_models from review import models as review_models from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions @@ -89,25 +89,32 @@ class MenuRUDSerializers(ProjectModelSerializer): class EstablishmentTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentType model.""" - name_translated = serializers.CharField(allow_null=True) + name_translated = TranslatedField() class Meta: """Meta class.""" model = models.EstablishmentType - fields = ('id', 'name_translated') + fields = ('id', 'name', 'name_translated') + extra_kwargs = { + 'name': {'write_only': True} + } class EstablishmentSubTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentSubType models.""" - name_translated = serializers.CharField(allow_null=True) + name_translated = TranslatedField() class Meta: """Meta class.""" model = models.EstablishmentSubType - fields = ('id', 'name_translated') + fields = ('id', 'name', 'name_translated', 'establishment_type') + extra_kwargs = { + 'name': {'write_only': True}, + 'establishment_type': {'write_only': True} + } class ReviewSerializer(serializers.ModelSerializer): @@ -138,14 +145,42 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): fields = ('id', 'name', 'position_translated', 'awards', 'priority') +class EstablishmentCategoryTagListSerializer(serializers.ModelSerializer): + """Serializer for establishment category tags.""" + label_translated = TranslatedField() + + class Meta: + """Meta class.""" + model = tag_models.TagCategory + fields = [ + 'id', + 'label_translated', + ] + + +class EstablishmentTagListSerializer(serializers.ModelSerializer): + """Serializer for establishment tags.""" + label_translated = TranslatedField(source='tag.label_translated') + category = EstablishmentCategoryTagListSerializer(source='tag.category') + + class Meta: + """Meta class.""" + model = tag_models.Tag + fields = [ + 'id', + 'label_translated', + 'category', + ] + + class EstablishmentBaseSerializer(ProjectModelSerializer): """Base serializer for Establishment model.""" preview_image = serializers.URLField(source='preview_image_url') slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) address = AddressBaseSerializer() - tags = MetaDataContentSerializer(many=True) in_favorites = serializers.BooleanField(allow_null=True) + tags = EstablishmentTagListSerializer(many=True) class Meta: """Meta class.""" @@ -305,18 +340,3 @@ class EstablishmentFavoritesCreateSerializer(serializers.ModelSerializer): 'content_object': validated_data.pop('establishment') }) return super().create(validated_data) - - -class EstablishmentTagListSerializer(serializers.ModelSerializer): - """List establishment tag serializer.""" - id = serializers.IntegerField(source='metadata.id') - label_translated = serializers.CharField( - source='metadata.label_translated', read_only=True, allow_null=True) - - class Meta: - """Meta class.""" - model = MetaDataContent - fields = [ - 'id', - 'label_translated', - ] diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index dca5fb55..b04a6843 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -14,6 +14,8 @@ urlpatterns = [ name='schedule-rud'), path('/schedule/', views.EstablishmentScheduleCreateView.as_view(), name='schedule-create'), + path('/tags/categories/', views.EstablishmentTagCategoryListView.as_view(), + name='tag-category-list'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), @@ -26,4 +28,8 @@ urlpatterns = [ path('emails//', views.EmailRUDView.as_view(), name='emails-rud'), path('employees/', views.EmployeeListCreateView.as_view(), name='employees'), path('employees//', views.EmployeeRUDView.as_view(), name='employees-rud'), + path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'), + path('types//', views.EstablishmentTypeRUDView.as_view(), name='type-rud'), + path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), + path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), ] \ No newline at end of file diff --git a/apps/establishment/urls/web.py b/apps/establishment/urls/web.py index b732d171..b4d1942d 100644 --- a/apps/establishment/urls/web.py +++ b/apps/establishment/urls/web.py @@ -4,4 +4,4 @@ from establishment.urls.common import urlpatterns as common_urlpatterns urlpatterns = [] -urlpatterns.extend(common_urlpatterns) \ No newline at end of file +urlpatterns.extend(common_urlpatterns) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 5cba8255..64887fb3 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,9 +1,9 @@ """Establishment app views.""" - +from django.shortcuts import get_object_or_404 from rest_framework import generics -from establishment import models -from establishment import serializers +from establishment import models, serializers +from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer class EstablishmentMixinViews: @@ -25,6 +25,62 @@ class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView): serializer_class = serializers.EstablishmentRUDSerializer +class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView): + """Establishment schedule RUD view""" + serializer_class = ScheduleRUDSerializer + + def get_object(self): + """ + Returns the object the view is displaying. + """ + establishment_pk = self.kwargs['pk'] + schedule_id = self.kwargs['schedule_id'] + + establishment = get_object_or_404(klass=models.Establishment.objects.all(), + pk=establishment_pk) + schedule = get_object_or_404(klass=establishment.schedule, + id=schedule_id) + + # May raise a permission denied + self.check_object_permissions(self.request, establishment) + self.check_object_permissions(self.request, schedule) + + return schedule + + +class EstablishmentScheduleCreateView(generics.CreateAPIView): + """Establishment schedule Create view""" + serializer_class = ScheduleCreateSerializer + + +class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.ListAPIView): + """View for establishment tag categories.""" + serializer_class = serializers.EstablishmentTagCategoryListSerializer + pagination_class = None + + def get_object(self): + """ + Returns the object the view is displaying. + """ + queryset = super(EstablishmentTagCategoryListView, self).get_queryset() + + # Perform the lookup filtering. + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + + filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} + obj = get_object_or_404(queryset, **filter_kwargs) + + # May raise a permission denied + self.check_object_permissions(self.request, obj) + + return obj + + def get_queryset(self): + """Overridden get_queryset method.""" + establishment = self.get_object() + return establishment.establishment_type.tag_categories.all() + + class MenuListCreateView(generics.ListCreateAPIView): """Menu list create view.""" serializer_class = serializers.MenuSerializers @@ -100,3 +156,35 @@ class EmployeeRUDView(generics.RetrieveUpdateDestroyAPIView): """Social RUD view.""" serializer_class = serializers.EmployeeBackSerializers queryset = models.Employee.objects.all() + + +class EstablishmentTypeListCreateView(generics.ListCreateAPIView): + """Establishment type list/create view.""" + serializer_class = serializers.EstablishmentTypeSerializer + queryset = models.EstablishmentType.objects.all() + pagination_class = None + + +class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView): + """Establishment type retrieve/update/destroy view.""" + serializer_class = serializers.EstablishmentTypeSerializer + queryset = models.EstablishmentType.objects.all() + + +class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView): + """Establishment subtype list/create view.""" + serializer_class = serializers.EstablishmentSubTypeSerializer + queryset = models.EstablishmentSubType.objects.all() + pagination_class = None + + +class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView): + """Establishment subtype retrieve/update/destroy view.""" + serializer_class = serializers.EstablishmentSubTypeSerializer + queryset = models.EstablishmentSubType.objects.all() + + +class EstablishmentTagListCreateView(generics.ListCreateAPIView): + """Establishment tag list/create view.""" + serializer_class = serializers.EstablishmentTagListSerializer + queryset = models.EstablishmentTag.objects.all() diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index 8f5d2a26..d65ede11 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -9,7 +9,6 @@ from establishment import filters from establishment import models, serializers from main import methods from main.models import MetaDataContent -from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer from utils.pagination import EstablishmentPortionPagination @@ -19,9 +18,10 @@ class EstablishmentMixinView: permission_classes = (permissions.AllowAny,) def get_queryset(self): - """Overrided method 'get_queryset'.""" - return models.Establishment.objects.published().with_base_related().\ - annotate_in_favorites(self.request.user) + """Overridden method 'get_queryset'.""" + return models.Establishment.objects.published() \ + .with_base_related() \ + .annotate_in_favorites(self.request.user) class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView): @@ -187,31 +187,3 @@ class EstablishmentTagListView(generics.ListAPIView): return MetaDataContent.objects.by_content_type(app_label='establishment', model='establishment')\ .distinct('metadata__label') - - -class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView): - """Establishment schedule RUD view""" - serializer_class = ScheduleRUDSerializer - - def get_object(self): - """ - Returns the object the view is displaying. - """ - establishment_pk = self.kwargs['pk'] - schedule_id = self.kwargs['schedule_id'] - - establishment = get_object_or_404(klass=models.Establishment.objects.all(), - pk=establishment_pk) - schedule = get_object_or_404(klass=establishment.schedule, - id=schedule_id) - - # May raise a permission denied - self.check_object_permissions(self.request, establishment) - self.check_object_permissions(self.request, schedule) - - return schedule - - -class EstablishmentScheduleCreateView(generics.CreateAPIView): - """Establishment schedule Create view""" - serializer_class = ScheduleCreateSerializer diff --git a/apps/main/admin.py b/apps/main/admin.py index bdbfe46e..f14a3470 100644 --- a/apps/main/admin.py +++ b/apps/main/admin.py @@ -25,22 +25,6 @@ class AwardAdmin(admin.ModelAdmin): # list_display_links = ['id', '__str__'] -@admin.register(models.MetaData) -class MetaDataAdmin(admin.ModelAdmin): - """MetaData admin.""" - - -@admin.register(models.MetaDataCategory) -class MetaDataCategoryAdmin(admin.ModelAdmin): - """MetaData admin.""" - list_display = ['id', 'country', 'content_type'] - - -@admin.register(models.MetaDataContent) -class MetaDataContentAdmin(admin.ModelAdmin): - """MetaDataContent admin""" - - @admin.register(models.Currency) class CurrencContentAdmin(admin.ModelAdmin): """CurrencContent admin""" diff --git a/apps/main/models.py b/apps/main/models.py index fa6cf7d1..df04fd8a 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -353,7 +353,6 @@ class Carousel(models.Model): return self.content_object.establishment_type.name_translated - class Page(models.Model): """Page model.""" diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index 2d43154e..3a06d4ed 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -30,17 +30,18 @@ class EstablishmentDocument(Document): properties=OBJECT_FIELD_PROPERTIES) }, multi=True) - tags = fields.ObjectField( - properties={ - 'id': fields.IntegerField(attr='metadata.id'), - 'label': fields.ObjectField(attr='metadata.label_indexing', - properties=OBJECT_FIELD_PROPERTIES), - 'category': fields.ObjectField(attr='metadata.category', - properties={ - 'id': fields.IntegerField(), - }) - }, - multi=True) + # todo: need to fix + # tags = fields.ObjectField( + # properties={ + # 'id': fields.IntegerField(attr='metadata.id'), + # 'label': fields.ObjectField(attr='metadata.label_indexing', + # properties=OBJECT_FIELD_PROPERTIES), + # 'category': fields.ObjectField(attr='metadata.category', + # properties={ + # 'id': fields.IntegerField(), + # }) + # }, + # multi=True) address = fields.ObjectField( properties={ 'id': fields.IntegerField(), diff --git a/apps/tag/__init__.py b/apps/tag/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/tag/admin.py b/apps/tag/admin.py new file mode 100644 index 00000000..ea7f9394 --- /dev/null +++ b/apps/tag/admin.py @@ -0,0 +1,12 @@ +from django.contrib import admin +from .models import Tag, TagCategory + + +@admin.register(Tag) +class TagAdmin(admin.ModelAdmin): + """Admin model for model Tag.""" + + +@admin.register(TagCategory) +class TagCategoryAdmin(admin.ModelAdmin): + """Admin model for model TagCategory.""" diff --git a/apps/tag/apps.py b/apps/tag/apps.py new file mode 100644 index 00000000..a1cce249 --- /dev/null +++ b/apps/tag/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class TagConfig(AppConfig): + name = 'tag' + verbose_name = _('tag') diff --git a/apps/tag/migrations/0001_initial.py b/apps/tag/migrations/0001_initial.py new file mode 100644 index 00000000..1c146570 --- /dev/null +++ b/apps/tag/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 2.2.4 on 2019-10-08 07:47 + +from django.db import migrations, models +import django.db.models.deletion +import utils.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('location', '0010_auto_20190904_0711'), + ] + + operations = [ + migrations.CreateModel( + name='TagCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='label')), + ('public', models.BooleanField(default=False)), + ('country', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Country')), + ], + options={ + 'verbose_name': 'tag category', + 'verbose_name_plural': 'tag categories', + }, + bases=(utils.models.TranslatedFieldsMixin, models.Model), + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='label')), + ('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tags', to='tag.TagCategory', verbose_name='category')), + ], + options={ + 'verbose_name': 'tag', + 'verbose_name_plural': 'tags', + }, + bases=(utils.models.TranslatedFieldsMixin, models.Model), + ), + ] diff --git a/apps/tag/migrations/__init__.py b/apps/tag/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/tag/models.py b/apps/tag/models.py new file mode 100644 index 00000000..c269d64e --- /dev/null +++ b/apps/tag/models.py @@ -0,0 +1,51 @@ +"""Tag app models.""" +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from configuration.models import TranslationSettings +from utils.models import TJSONField, TranslatedFieldsMixin + + +class Tag(TranslatedFieldsMixin, models.Model): + """Tag model.""" + label = TJSONField( + _('label'), null=True, blank=True, + default=None, help_text='{"en-GB":"some text"}') + category = models.ForeignKey('TagCategory', + on_delete=models.SET_NULL, null=True, + related_name='tags', + verbose_name='category') + + class Meta: + verbose_name = _('tag') + verbose_name_plural = _('tags') + + def __str__(self): + label = 'None' + lang = TranslationSettings.get_solo().default_language + if self.label and lang in self.label: + label = self.label[lang] + return f'id:{self.id}-{label}' + + +class TagCategory(TranslatedFieldsMixin, models.Model): + """Tag base category model.""" + label = TJSONField( + _('label'), null=True, blank=True, + default=None, help_text='{"en-GB":"some text"}') + country = models.ForeignKey('location.Country', + on_delete=models.SET_NULL, null=True, + default=None) + + public = models.BooleanField(default=False) + + class Meta: + verbose_name = _('tag category') + verbose_name_plural = _('tag categories') + + def __str__(self): + label = 'None' + lang = TranslationSettings.get_solo().default_language + if self.label and lang in self.label: + label = self.label[lang] + return f'id:{self.id}-{label}' diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py new file mode 100644 index 00000000..cf783910 --- /dev/null +++ b/apps/tag/serializers.py @@ -0,0 +1,44 @@ +"""Tag serializers.""" +from rest_framework import serializers +from . import models +from utils.serializers import TranslatedField + + +class TagBaseSerializer(serializers.ModelSerializer): + """Serializer for model Tag.""" + label_translated = TranslatedField() + + class Meta: + model = models.Tag + fields = [ + 'id', + 'label', + 'label_translated', + 'category' + ] + extra_kwargs = { + 'label': {'write_only': True}, + 'category': {'write_only': True} + } + + +class TagCategoryBaseSerializer(serializers.ModelSerializer): + """Serializer for model TagCategory.""" + label_translated = TranslatedField() + country_translated = TranslatedField(source='country.name_translated') + + class Meta: + """Meta class.""" + model = models.TagCategory + fields = [ + 'id', + 'label', + 'label_translated', + 'country', + 'country_translated', + 'public', + ] + extra_kwargs = { + 'label': {'write_only': True}, + 'country': {'write_only': True}, + } diff --git a/apps/tag/tests.py b/apps/tag/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/tag/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/tag/urls.py b/apps/tag/urls.py new file mode 100644 index 00000000..0d0b86d2 --- /dev/null +++ b/apps/tag/urls.py @@ -0,0 +1,10 @@ +"""Urlconf for app tag.""" +from django.urls import path +from . import views + +app_name = 'tag' + +urlpatterns = [ + path('', views.TagListCreateView.as_view(), name='list-create'), + path('category/', views.TagCategoryListCreateView.as_view(), name='category-list-create'), +] diff --git a/apps/tag/views.py b/apps/tag/views.py new file mode 100644 index 00000000..ab944ba7 --- /dev/null +++ b/apps/tag/views.py @@ -0,0 +1,18 @@ +"""Tag views.""" +from rest_framework import generics + +from . import serializers, models + + +class TagListCreateView(generics.ListCreateAPIView): + """List/create tag view.""" + queryset = models.Tag.objects.all() + serializer_class = serializers.TagBaseSerializer + pagination_class = None + + +class TagCategoryListCreateView(generics.ListCreateAPIView): + """List/create tag category view.""" + queryset = models.TagCategory.objects.all() + serializer_class = serializers.TagCategoryBaseSerializer + pagination_class = None diff --git a/project/settings/base.py b/project/settings/base.py index cec6a4d1..8f02f52d 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -72,6 +72,7 @@ PROJECT_APPS = [ 'comment.apps.CommentConfig', 'favorites.apps.FavoritesConfig', 'rating.apps.RatingConfig', + 'tag.apps.TagConfig', ] EXTERNAL_APPS = [ diff --git a/project/urls/back.py b/project/urls/back.py index 7b4146eb..2a9657db 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -7,5 +7,7 @@ urlpatterns = [ namespace='gallery')), path('establishments/', include('establishment.urls.back')), path('location/', include('location.urls.back')), - path('news/', include('news.urls.back')) -] \ No newline at end of file + path('news/', include('news.urls.back')), + path('tags/', include(('tag.urls', 'tag'), + namespace='tag')) +] From 69d02e7a07eb573d03f6dea0210379677ac2067a Mon Sep 17 00:00:00 2001 From: Anatoly Date: Wed, 9 Oct 2019 10:05:19 +0300 Subject: [PATCH 02/25] fix auth --- apps/utils/authentication.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/utils/authentication.py b/apps/utils/authentication.py index 044d6d75..e8375ffe 100644 --- a/apps/utils/authentication.py +++ b/apps/utils/authentication.py @@ -23,14 +23,24 @@ class GMJWTAuthentication(JWTAuthentication): """ def authenticate(self, request): - token = get_token_from_cookies(request) - if token is None: + try: + token = get_token_from_cookies(request) + # Return non-authorized user if token not in cookies + assert token + + raw_token = self.get_raw_token(token) + # Return non-authorized user if cant get raw token + assert raw_token + + validated_token = self.get_validated_token(raw_token) + user = self.get_user(validated_token) + + # Check record in DB + token_is_valid = user.access_tokens.valid() \ + .by_jti(jti=validated_token.payload.get('jti')) + assert token_is_valid.exists() + except: + # Return non-authorized user if token is invalid or raised an error when run checks. return None - - raw_token = self.get_raw_token(token) - if raw_token is None: - return None - - validated_token = self.get_validated_token(raw_token) - - return self.get_user(validated_token), None + else: + return user, None From ca5f588466602381dc5a8bf0e0a8ff85f523c567 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Wed, 9 Oct 2019 12:53:35 +0300 Subject: [PATCH 03/25] fix elastic document, fix prefetch and select related --- apps/authorization/tasks.py | 4 +-- ...ishmenttag_establishmenttypetagcategory.py | 28 +++++++--------- .../migrations/0033_auto_20191009_0715.py | 30 +++++++++++++++++ apps/establishment/models.py | 22 ++++++------- apps/establishment/serializers/back.py | 1 + .../search_indexes/documents/establishment.py | 32 +++++++++++-------- apps/tag/migrations/0001_initial.py | 2 +- project/settings/base.py | 6 ++-- 8 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 apps/establishment/migrations/0033_auto_20191009_0715.py diff --git a/apps/authorization/tasks.py b/apps/authorization/tasks.py index c97fbbae..cb186142 100644 --- a/apps/authorization/tasks.py +++ b/apps/authorization/tasks.py @@ -1,10 +1,10 @@ """Authorization app celery tasks.""" import logging -from django.utils.translation import gettext_lazy as _ + from celery import shared_task +from django.utils.translation import gettext_lazy as _ from account import models as account_models -from smtplib import SMTPException logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py b/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py index 6efaa57a..ec9966d8 100644 --- a/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py +++ b/apps/establishment/migrations/0032_establishmenttag_establishmenttypetagcategory.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-10-08 07:47 +# Generated by Django 2.2.4 on 2019-10-09 07:15 from django.db import migrations, models import django.db.models.deletion @@ -7,33 +7,29 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('tag', '0001_initial'), ('establishment', '0031_establishment_slug'), ] operations = [ - migrations.CreateModel( - name='EstablishmentTypeTagCategory', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('establishment_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tag_categories', to='establishment.EstablishmentType', verbose_name='establishment type')), - ('tag_category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='est_type_tag_categories', to='tag.TagCategory', verbose_name='tag category')), - ], - options={ - 'verbose_name': 'establishment type tag categories', - 'verbose_name_plural': 'establishment type tag categories', - }, - ), migrations.CreateModel( name='EstablishmentTag', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('establishment', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tags', to='establishment.Establishment', verbose_name='establishment')), - ('tag', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tags', to='tag.Tag', verbose_name='tag')), ], options={ 'verbose_name': 'establishment tag', 'verbose_name_plural': 'establishment tags', }, ), + migrations.CreateModel( + name='EstablishmentTypeTagCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('establishment_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tag_categories', to='establishment.EstablishmentType', verbose_name='establishment type')), + ], + options={ + 'verbose_name': 'establishment type tag categories', + 'verbose_name_plural': 'establishment type tag categories', + }, + ), ] diff --git a/apps/establishment/migrations/0033_auto_20191009_0715.py b/apps/establishment/migrations/0033_auto_20191009_0715.py new file mode 100644 index 00000000..5df367d6 --- /dev/null +++ b/apps/establishment/migrations/0033_auto_20191009_0715.py @@ -0,0 +1,30 @@ +# Generated by Django 2.2.4 on 2019-10-09 07:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0001_initial'), + ('establishment', '0032_establishmenttag_establishmenttypetagcategory'), + ] + + operations = [ + migrations.AddField( + model_name='establishmenttypetagcategory', + name='tag_category', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='est_type_tag_categories', to='tag.TagCategory', verbose_name='tag category'), + ), + migrations.AddField( + model_name='establishmenttag', + name='establishment', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='establishment.Establishment', verbose_name='establishment'), + ), + migrations.AddField( + model_name='establishmenttag', + name='tag', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='tag.Tag', verbose_name='tag'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 9ce4eebc..30ca88bd 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -15,6 +15,7 @@ from elasticsearch_dsl import Q from phonenumber_field.modelfields import PhoneNumberField from collection.models import Collection +from tag.models import Tag, TagCategory from main.models import Award, MetaDataContent from location.models import Address from review.models import Review @@ -76,13 +77,12 @@ class EstablishmentQuerySet(models.QuerySet): def with_base_related(self): """Return qs with related objects.""" - return self.select_related('address') - # todo: fix this - # return self.select_related('address').prefetch_related( - # models.Prefetch('tags', - # MetaDataContent.objects.select_related( - # 'metadata__category')) - # ) + return self.select_related('address', 'establishment_type').prefetch_related( + models.Prefetch('tags', + EstablishmentTag.objects.select_related('tag')), + models.Prefetch('establishment_type__tag_categories', + EstablishmentTypeTagCategory.objects.select_related('tag_category')), + ) def with_extended_related(self): return self.select_related('establishment_type').\ @@ -561,11 +561,11 @@ class EstablishmentTagQuerySet(models.QuerySet): class EstablishmentTag(models.Model): """Establishment tag model.""" tag = models.ForeignKey('tag.Tag', - on_delete=models.SET_NULL, null=True, + on_delete=models.CASCADE, related_name='tags', verbose_name=_('tag')) establishment = models.ForeignKey('establishment.Establishment', - on_delete=models.SET_NULL, null=True, + on_delete=models.CASCADE, related_name='tags', verbose_name=_('establishment')) objects = EstablishmentTagQuerySet.as_manager() @@ -586,11 +586,11 @@ class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): class EstablishmentTypeTagCategory(models.Model): """Tag categories based on establishment type.""" establishment_type = models.ForeignKey(EstablishmentType, - on_delete=models.SET_NULL, null=True, + on_delete=models.CASCADE, related_name='tag_categories', verbose_name=_('establishment type')) tag_category = models.ForeignKey('tag.TagCategory', - on_delete=models.SET_NULL, null=True, + on_delete=models.CASCADE, related_name='est_type_tag_categories', verbose_name=_('tag category')) objects = EstablishmentTypeTagCategoryQuerySet.as_manager() diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index b15ff51f..766806ad 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -78,6 +78,7 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer): class EstablishmentTagCategoryListSerializer(serializers.ModelSerializer): """Serializer for intermediate model EstablishmentTypeTagCategories.""" + id = serializers.IntegerField(source='tag_category.id') label_translated = TranslatedField(source='tag_category.label_translated') tags = TagBaseSerializer(source='tag_category.tags', many=True) diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index 3a06d4ed..e2147fbc 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -21,27 +21,31 @@ class EstablishmentDocument(Document): properties={ 'id': fields.IntegerField(), 'name': fields.ObjectField(attr='name_indexing', - properties=OBJECT_FIELD_PROPERTIES) + properties=OBJECT_FIELD_PROPERTIES), + 'tag_categories': fields.ObjectField(properties={ + 'tag_category': fields.ObjectField( + properties={ + 'id': fields.IntegerField() + } + ) + }), }) establishment_subtypes = fields.ObjectField( properties={ 'id': fields.IntegerField(), 'name': fields.ObjectField(attr='name_indexing', - properties=OBJECT_FIELD_PROPERTIES) + properties={ + 'id': fields.IntegerField(), + }), + }, + multi=True) + tags = fields.ObjectField( + properties={ + 'tag': fields.ObjectField(properties={ + 'id': fields.IntegerField(), + }), }, multi=True) - # todo: need to fix - # tags = fields.ObjectField( - # properties={ - # 'id': fields.IntegerField(attr='metadata.id'), - # 'label': fields.ObjectField(attr='metadata.label_indexing', - # properties=OBJECT_FIELD_PROPERTIES), - # 'category': fields.ObjectField(attr='metadata.category', - # properties={ - # 'id': fields.IntegerField(), - # }) - # }, - # multi=True) address = fields.ObjectField( properties={ 'id': fields.IntegerField(), diff --git a/apps/tag/migrations/0001_initial.py b/apps/tag/migrations/0001_initial.py index 1c146570..543eb035 100644 --- a/apps/tag/migrations/0001_initial.py +++ b/apps/tag/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-10-08 07:47 +# Generated by Django 2.2.4 on 2019-10-09 07:15 from django.db import migrations, models import django.db.models.deletion diff --git a/project/settings/base.py b/project/settings/base.py index 8f02f52d..f04788d1 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -282,9 +282,9 @@ SMS_SENDER = 'GM' # EMAIL EMAIL_USE_TLS = True -EMAIL_HOST = 'smtp.yandex.ru' -EMAIL_HOST_USER = 't3st.t3stov.t3stovich@yandex.ru' -EMAIL_HOST_PASSWORD = 'ylhernyutkfbylgk' +EMAIL_HOST = 'smtp.mandrillapp.com' +EMAIL_HOST_USER = 'bbody@gaultmillau.fr' +EMAIL_HOST_PASSWORD = 'FQghjXmS1FmKmlZEpSg6TA' EMAIL_PORT = 587 # Django Rest Swagger From 2191a505a59b6f6202dfcb8bcb03786885e45826 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Wed, 9 Oct 2019 14:11:53 +0300 Subject: [PATCH 04/25] refactored EstablishmentBase serializer --- apps/establishment/serializers/back.py | 18 ----------- apps/establishment/serializers/common.py | 38 +++++++++++++++++------- apps/establishment/urls/common.py | 1 - apps/establishment/views/back.py | 9 +++--- apps/establishment/views/web.py | 13 -------- 5 files changed, 33 insertions(+), 46 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 766806ad..d0c70b2f 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,5 +1,4 @@ from rest_framework import serializers -from tag.serializers import TagBaseSerializer from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, @@ -7,7 +6,6 @@ from establishment.serializers import ( EstablishmentTypeSerializer) from utils.decorators import with_base_attributes -from utils.serializers import TranslatedField from main.models import Currency @@ -76,22 +74,6 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer): ] -class EstablishmentTagCategoryListSerializer(serializers.ModelSerializer): - """Serializer for intermediate model EstablishmentTypeTagCategories.""" - id = serializers.IntegerField(source='tag_category.id') - label_translated = TranslatedField(source='tag_category.label_translated') - tags = TagBaseSerializer(source='tag_category.tags', many=True) - - class Meta: - """Meta class.""" - model = models.EstablishmentTypeTagCategory - fields = [ - 'id', - 'label_translated', - 'tags', - ] - - class SocialNetworkSerializers(serializers.ModelSerializer): """Social network serializers.""" class Meta: diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 6c12360b..2cd4e429 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -1,17 +1,20 @@ """Establishment serializers.""" from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers + from comment import models as comment_models from comment.serializers import common as comment_serializers from establishment import models from favorites.models import Favorites from location.serializers import AddressBaseSerializer from main.serializers import AwardSerializer, CurrencySerializer -from tag import models as tag_models from review import models as review_models +from tag import models as tag_models +from tag.serializers import TagBaseSerializer from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions -from utils.serializers import TranslatedField, ProjectModelSerializer +from utils.serializers import ProjectModelSerializer +from utils.serializers import TranslatedField class ContactPhonesSerializer(serializers.ModelSerializer): @@ -86,6 +89,22 @@ class MenuRUDSerializers(ProjectModelSerializer): ] +class EstablishmentTagCategoryListSerializer(serializers.ModelSerializer): + """Serializer for intermediate model EstablishmentTypeTagCategories.""" + id = serializers.IntegerField(source='tag_category.id') + label_translated = TranslatedField(source='tag_category.label_translated') + tags = TagBaseSerializer(source='tag_category.tags', many=True) + + class Meta: + """Meta class.""" + model = models.EstablishmentTypeTagCategory + fields = [ + 'id', + 'label_translated', + 'tags', + ] + + class EstablishmentTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentType model.""" @@ -158,18 +177,17 @@ class EstablishmentCategoryTagListSerializer(serializers.ModelSerializer): ] -class EstablishmentTagListSerializer(serializers.ModelSerializer): - """Serializer for establishment tags.""" - label_translated = TranslatedField(source='tag.label_translated') - category = EstablishmentCategoryTagListSerializer(source='tag.category') +class EstablishmentTagSerializer(serializers.ModelSerializer): + """Serializer for intermediate model EstablishmentTag.""" + id = serializers.IntegerField(source='tag.id') + label_translated = serializers.CharField(source='tag.label_translated') class Meta: """Meta class.""" - model = tag_models.Tag + model = models.EstablishmentTag fields = [ 'id', - 'label_translated', - 'category', + 'label_translated' ] @@ -180,7 +198,7 @@ class EstablishmentBaseSerializer(ProjectModelSerializer): slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) address = AddressBaseSerializer() in_favorites = serializers.BooleanField(allow_null=True) - tags = EstablishmentTagListSerializer(many=True) + tags = EstablishmentTagSerializer(many=True) class Meta: """Meta class.""" diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 1e9225d6..5d7df146 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -7,7 +7,6 @@ app_name = 'establishment' urlpatterns = [ path('', views.EstablishmentListView.as_view(), name='list'), - path('tags/', views.EstablishmentTagListView.as_view(), name='tags'), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), name='recent-reviews'), path('slug//', views.EstablishmentRetrieveView.as_view(), name='detail'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 64887fb3..32ee2805 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -184,7 +184,8 @@ class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = models.EstablishmentSubType.objects.all() -class EstablishmentTagListCreateView(generics.ListCreateAPIView): - """Establishment tag list/create view.""" - serializer_class = serializers.EstablishmentTagListSerializer - queryset = models.EstablishmentTag.objects.all() +# todo: next task +# class EstablishmentTagListCreateView(generics.CreateAPIView): +# """Establishment tag list/create view.""" +# serializer_class = serializers.EstablishmentTagCategoryListCreateSerializer +# queryset = models.EstablishmentTag.objects.all() diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index d65ede11..b4ef4f13 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -174,16 +174,3 @@ class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIVi return qs.by_distance_from_point(**{k: v for k, v in filter_kwargs.items() if v is not None}) return qs - - -class EstablishmentTagListView(generics.ListAPIView): - """List view for establishment tags.""" - serializer_class = serializers.EstablishmentTagListSerializer - permission_classes = (permissions.AllowAny,) - pagination_class = None - - def get_queryset(self): - """Override get_queryset method""" - return MetaDataContent.objects.by_content_type(app_label='establishment', - model='establishment')\ - .distinct('metadata__label') From 31f8b5abd12ad2a6b195cc1c1ed21a97eb7168e7 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Wed, 9 Oct 2019 15:19:46 +0300 Subject: [PATCH 05/25] refactored base settings --- project/settings/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/project/settings/base.py b/project/settings/base.py index cec6a4d1..2a6f4aea 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -275,15 +275,15 @@ SMS_CODE_SHOW = False # SMSC Settings SMS_SERVICE = 'http://smsc.ru/sys/send.php' -SMS_LOGIN = 'GM2019' -SMS_PASSWORD = '}#6%Qe7CYG7n' +SMS_LOGIN = os.environ.get('SMS_LOGIN') +SMS_PASSWORD = os.environ.get('SMS_PASSWORD') SMS_SENDER = 'GM' # EMAIL EMAIL_USE_TLS = True -EMAIL_HOST = 'smtp.yandex.ru' -EMAIL_HOST_USER = 't3st.t3stov.t3stovich@yandex.ru' -EMAIL_HOST_PASSWORD = 'ylhernyutkfbylgk' +EMAIL_HOST = 'smtp.mandrillapp.com' +EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD') EMAIL_PORT = 587 # Django Rest Swagger From 074a5ec5ea7be3450ec89b79c7b278c8a6a09464 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Wed, 9 Oct 2019 18:25:40 +0300 Subject: [PATCH 06/25] refactor news tags --- .../migrations/0021_auto_20191009_1408.py | 24 ++++++++++ apps/news/models.py | 7 +-- apps/news/serializers.py | 4 +- apps/news/urls/web.py | 2 + apps/news/views.py | 16 +++++++ .../tag/migrations/0002_auto_20191009_1408.py | 27 +++++++++++ apps/tag/models.py | 47 ++++++++++++------- apps/tag/serializers.py | 21 +++++++-- apps/tag/views.py | 5 +- project/urls/back.py | 6 +-- project/urls/web.py | 3 +- 11 files changed, 131 insertions(+), 31 deletions(-) create mode 100644 apps/news/migrations/0021_auto_20191009_1408.py create mode 100644 apps/tag/migrations/0002_auto_20191009_1408.py diff --git a/apps/news/migrations/0021_auto_20191009_1408.py b/apps/news/migrations/0021_auto_20191009_1408.py new file mode 100644 index 00000000..81a4d7fa --- /dev/null +++ b/apps/news/migrations/0021_auto_20191009_1408.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.4 on 2019-10-09 14:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0002_auto_20191009_1408'), + ('news', '0020_remove_news_author'), + ] + + operations = [ + migrations.AddField( + model_name='news', + name='tags', + field=models.ManyToManyField(related_name='news', to='tag.Tag', verbose_name='Tags'), + ), + migrations.AddField( + model_name='newstype', + name='tag_categories', + field=models.ManyToManyField(related_name='news_types', to='tag.TagCategory'), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 6e91b912..8a6a89f4 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -12,6 +12,8 @@ class NewsType(models.Model): """NewsType model.""" name = models.CharField(_('name'), max_length=250) + tag_categories = models.ManyToManyField('tag.TagCategory', + related_name='news_types') class Meta: """Meta class.""" @@ -133,8 +135,8 @@ class News(BaseAttributes, TranslatedFieldsMixin): country = models.ForeignKey('location.Country', blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('country')) - tags = generic.GenericRelation(to='main.MetaDataContent') - + tags = models.ManyToManyField('tag.Tag', related_name='news', + verbose_name=_('Tags')) ratings = generic.GenericRelation(Rating) objects = NewsQuerySet.as_manager() @@ -163,4 +165,3 @@ class News(BaseAttributes, TranslatedFieldsMixin): @property def same_theme(self): return self.__class__.objects.same_theme(self)[:3] - diff --git a/apps/news/serializers.py b/apps/news/serializers.py index c473be1d..6f0b73b6 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -3,8 +3,8 @@ from rest_framework import serializers from account.serializers.common import UserBaseSerializer from location import models as location_models from location.serializers import CountrySimpleSerializer -from main.serializers import MetaDataContentSerializer from news import models +from tag.serializers import TagBaseSerializer from utils.serializers import TranslatedField, ProjectModelSerializer @@ -27,7 +27,7 @@ class NewsBaseSerializer(ProjectModelSerializer): # related fields news_type = NewsTypeSerializer(read_only=True) - tags = MetaDataContentSerializer(read_only=True, many=True) + tags = TagBaseSerializer(read_only=True, many=True) class Meta: """Meta class.""" diff --git a/apps/news/urls/web.py b/apps/news/urls/web.py index 80fcf072..0671f5f6 100644 --- a/apps/news/urls/web.py +++ b/apps/news/urls/web.py @@ -7,5 +7,7 @@ app_name = 'news' urlpatterns = [ path('', views.NewsListView.as_view(), name='list'), path('types/', views.NewsTypeListView.as_view(), name='type'), + path('types//tags/', views.NewsTypeTagsView.as_view(), + name='type-tags'), path('slug//', views.NewsDetailView.as_view(), name='rud'), ] diff --git a/apps/news/views.py b/apps/news/views.py index 61a57251..1a845a7b 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -1,7 +1,10 @@ """News app views.""" +from django.shortcuts import get_object_or_404 from rest_framework import generics, permissions from news import filters, models, serializers from rating.tasks import add_rating +from tag.serializers import TagCategoryDetailSerializer + class NewsMixinView: """News mixin.""" @@ -34,6 +37,7 @@ class NewsDetailView(NewsMixinView, generics.RetrieveAPIView): """Override get_queryset method.""" return super().get_queryset().with_extended_related() + class NewsTypeListView(generics.ListAPIView): """NewsType list view.""" @@ -43,6 +47,18 @@ class NewsTypeListView(generics.ListAPIView): serializer_class = serializers.NewsTypeSerializer +class NewsTypeTagsView(generics.ListAPIView): + """Resource to get a list of tags for a news type.""" + + pagination_class = None + permission_classes = (permissions.AllowAny, ) + serializer_class = TagCategoryDetailSerializer + + def get_queryset(self): + news_type = get_object_or_404(models.NewsType, pk=self.kwargs.get('pk')) + return news_type.tag_categories.with_related() + + class NewsBackOfficeMixinView: """News back office mixin view.""" diff --git a/apps/tag/migrations/0002_auto_20191009_1408.py b/apps/tag/migrations/0002_auto_20191009_1408.py new file mode 100644 index 00000000..472d9596 --- /dev/null +++ b/apps/tag/migrations/0002_auto_20191009_1408.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2.4 on 2019-10-09 14:08 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='tag', + options={'verbose_name': 'Tag', 'verbose_name_plural': 'Tags'}, + ), + migrations.AlterModelOptions( + name='tagcategory', + options={'verbose_name': 'Tag category', 'verbose_name_plural': 'Tag categories'}, + ), + migrations.AlterField( + model_name='tag', + name='category', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tags', to='tag.TagCategory', verbose_name='Category'), + ), + ] diff --git a/apps/tag/models.py b/apps/tag/models.py index c269d64e..b552bbcb 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -1,24 +1,25 @@ """Tag app models.""" from django.db import models from django.utils.translation import gettext_lazy as _ - from configuration.models import TranslationSettings from utils.models import TJSONField, TranslatedFieldsMixin class Tag(TranslatedFieldsMixin, models.Model): """Tag model.""" - label = TJSONField( - _('label'), null=True, blank=True, - default=None, help_text='{"en-GB":"some text"}') - category = models.ForeignKey('TagCategory', - on_delete=models.SET_NULL, null=True, - related_name='tags', - verbose_name='category') + + label = TJSONField(blank=True, null=True, default=None, + verbose_name=_('label'), + help_text='{"en-GB":"some text"}') + category = models.ForeignKey('TagCategory', on_delete=models.PROTECT, + null=True, related_name='tags', + verbose_name=_('Category')) class Meta: - verbose_name = _('tag') - verbose_name_plural = _('tags') + """Meta class.""" + + verbose_name = _('Tag') + verbose_name_plural = _('Tags') def __str__(self): label = 'None' @@ -28,20 +29,34 @@ class Tag(TranslatedFieldsMixin, models.Model): return f'id:{self.id}-{label}' +class TagCategoryQuerySet(models.QuerySet): + """Extended queryset for TagCategory model.""" + + def by_news_type(self, news_type): + return self.filter(news_types=news_type) + + def with_related(self): + return self.select_related('country').prefetch_related('tags') + + class TagCategory(TranslatedFieldsMixin, models.Model): """Tag base category model.""" - label = TJSONField( - _('label'), null=True, blank=True, - default=None, help_text='{"en-GB":"some text"}') + + label = TJSONField(blank=True, null=True, default=None, + verbose_name=_('label'), + help_text='{"en-GB":"some text"}') country = models.ForeignKey('location.Country', on_delete=models.SET_NULL, null=True, default=None) - public = models.BooleanField(default=False) + objects = TagCategoryQuerySet.as_manager() + class Meta: - verbose_name = _('tag category') - verbose_name_plural = _('tag categories') + """Meta class.""" + + verbose_name = _('Tag category') + verbose_name_plural = _('Tag categories') def __str__(self): label = 'None' diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index cf783910..ecb1b68d 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -1,14 +1,17 @@ """Tag serializers.""" from rest_framework import serializers -from . import models +from tag import models from utils.serializers import TranslatedField class TagBaseSerializer(serializers.ModelSerializer): """Serializer for model Tag.""" + label_translated = TranslatedField() class Meta: + """Meta class.""" + model = models.Tag fields = [ 'id', @@ -24,21 +27,33 @@ class TagBaseSerializer(serializers.ModelSerializer): class TagCategoryBaseSerializer(serializers.ModelSerializer): """Serializer for model TagCategory.""" + label_translated = TranslatedField() country_translated = TranslatedField(source='country.name_translated') class Meta: """Meta class.""" + model = models.TagCategory - fields = [ + fields = ( 'id', 'label', 'label_translated', 'country', 'country_translated', 'public', - ] + ) extra_kwargs = { 'label': {'write_only': True}, 'country': {'write_only': True}, } + + +class TagCategoryDetailSerializer(TagCategoryBaseSerializer): + + tags = TagBaseSerializer(many=True) + + class Meta(TagCategoryBaseSerializer.Meta): + """Meta class.""" + + fields = TagCategoryBaseSerializer.Meta.fields + ('tags', ) diff --git a/apps/tag/views.py b/apps/tag/views.py index ab944ba7..5bf4d045 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -1,11 +1,11 @@ """Tag views.""" from rest_framework import generics - -from . import serializers, models +from tag import serializers, models class TagListCreateView(generics.ListCreateAPIView): """List/create tag view.""" + queryset = models.Tag.objects.all() serializer_class = serializers.TagBaseSerializer pagination_class = None @@ -13,6 +13,7 @@ class TagListCreateView(generics.ListCreateAPIView): class TagCategoryListCreateView(generics.ListCreateAPIView): """List/create tag category view.""" + queryset = models.TagCategory.objects.all() serializer_class = serializers.TagCategoryBaseSerializer pagination_class = None diff --git a/project/urls/back.py b/project/urls/back.py index 2a9657db..77e573d0 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -3,11 +3,9 @@ from django.urls import path, include app_name = 'back' urlpatterns = [ - path('gallery/', include(('gallery.urls', 'gallery'), - namespace='gallery')), + path('gallery/', include(('gallery.urls', 'gallery'), namespace='gallery')), path('establishments/', include('establishment.urls.back')), path('location/', include('location.urls.back')), path('news/', include('news.urls.back')), - path('tags/', include(('tag.urls', 'tag'), - namespace='tag')) + path('tags/', include(('tag.urls', 'tag'), namespace='tag')) ] diff --git a/project/urls/web.py b/project/urls/web.py index 5bf538f3..a4e68317 100644 --- a/project/urls/web.py +++ b/project/urls/web.py @@ -23,7 +23,8 @@ urlpatterns = [ path('collections/', include('collection.urls.web')), path('establishments/', include('establishment.urls.web')), path('news/', include('news.urls.web')), - path('notifications/', include(('notification.urls.web', "notification"), namespace='notification')), + path('notifications/', include(('notification.urls.web', "notification"), + namespace='notification')), path('partner/', include('partner.urls.web')), path('location/', include('location.urls.web')), path('main/', include('main.urls')), From f83b735eb321306dfa6a710e3f820bb12d14dcab Mon Sep 17 00:00:00 2001 From: Anatoly Date: Thu, 10 Oct 2019 15:10:43 +0300 Subject: [PATCH 07/25] changed files --- .../migrations/0034_merge_20191009_1457.py | 14 ++++++ apps/establishment/models.py | 27 ++++++++++++ apps/establishment/serializers/back.py | 5 +-- apps/establishment/serializers/common.py | 44 +++++++++++++++++-- apps/establishment/urls/back.py | 4 ++ apps/establishment/views/back.py | 30 ++++++++++++- 6 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 apps/establishment/migrations/0034_merge_20191009_1457.py diff --git a/apps/establishment/migrations/0034_merge_20191009_1457.py b/apps/establishment/migrations/0034_merge_20191009_1457.py new file mode 100644 index 00000000..945860f7 --- /dev/null +++ b/apps/establishment/migrations/0034_merge_20191009_1457.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2019-10-09 14:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0033_auto_20191009_0715'), + ('establishment', '0033_auto_20191003_0943_squashed_0034_auto_20191003_1036'), + ] + + operations = [ + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 74348f5d..c248ca5d 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -479,6 +479,7 @@ class ContactEmail(models.Model): def __str__(self): return f'{self.email}' + # # class Wine(TranslatedFieldsMixin, models.Model): # """Wine model.""" @@ -586,6 +587,11 @@ class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): """Return establishment tags by country code""" return self.filter(tag_category__country__code=code) + def with_base_related(self): + """Return with related relations.""" + # return self.select_related('tags', 'establishment_type') + return self.select_related('establishment_type', 'tag_category') + class EstablishmentTypeTagCategory(models.Model): """Tag categories based on establishment type.""" @@ -602,3 +608,24 @@ class EstablishmentTypeTagCategory(models.Model): class Meta: verbose_name = _('establishment type tag categories') verbose_name_plural = _('establishment type tag categories') + + +# class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet): +# """QuerySet for tag categories based on establishment subtype.""" +# +# +# class EstablishmentSubTypeTagCategory(models.Model): +# """Tag categories based on establishment subtype.""" +# establishment_subtype = models.ForeignKey(EstablishmentSubType, +# on_delete=models.CASCADE, +# related_name='tag_categories', +# verbose_name=_('establishment subtype')) +# tag_category = models.ForeignKey('tag.TagCategory', +# on_delete=models.CASCADE, +# related_name='est_subtype_tag_categories', +# verbose_name=_('tag category')) +# objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager() +# +# class Meta: +# verbose_name = _('establishment subtype tag categories') +# verbose_name_plural = _('establishment subtype tag categories') diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 8bd09e85..33d2e812 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,13 +1,12 @@ from rest_framework import serializers + from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, ContactPhonesSerializer, SocialNetworkRelatedSerializers, EstablishmentTypeSerializer) - -from utils.decorators import with_base_attributes - from main.models import Currency +from utils.decorators import with_base_attributes class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 2cd4e429..ef21e4fb 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -89,11 +89,11 @@ class MenuRUDSerializers(ProjectModelSerializer): ] -class EstablishmentTagCategoryListSerializer(serializers.ModelSerializer): +class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): """Serializer for intermediate model EstablishmentTypeTagCategories.""" - id = serializers.IntegerField(source='tag_category.id') + id = serializers.IntegerField(source='tag_category.id', read_only=True) label_translated = TranslatedField(source='tag_category.label_translated') - tags = TagBaseSerializer(source='tag_category.tags', many=True) + tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) class Meta: """Meta class.""" @@ -102,7 +102,21 @@ class EstablishmentTagCategoryListSerializer(serializers.ModelSerializer): 'id', 'label_translated', 'tags', + 'establishment_type', + 'tag_category', ] + extra_kwargs = { + 'establishment_type': {'write_only': True}, + 'tag_category': {'write_only': True}, + } + + def validate(self, attrs): + """Override validate method.""" + if models.EstablishmentTypeTagCategory.objects.filter( + establishment_type=attrs.get('establishment_type'), + tag_category=attrs.get('tag_category')).exists(): + raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) + return attrs class EstablishmentTypeSerializer(serializers.ModelSerializer): @@ -136,6 +150,30 @@ class EstablishmentSubTypeSerializer(serializers.ModelSerializer): } +# class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): +# """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" +# +# class Meta: +# """Meta class.""" +# model = models.EstablishmentSubTypeTagCategory +# fields = [ +# 'establishment_subtype', +# 'tag_category', +# ] +# extra_kwargs = { +# 'establishment_subtype': {'write_only': True}, +# 'tag_category': {'write_only': True}, +# } +# +# def validate(self, attrs): +# """Override validate method.""" +# if models.EstablishmentSubTypeTagCategory.objects.filter( +# establishment_type=attrs.get('establishment_subtype'), +# tag_category=attrs.get('tag_category')).exists(): +# raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) +# return attrs + + class ReviewSerializer(serializers.ModelSerializer): """Serializer for model Review.""" text_translated = serializers.CharField(read_only=True) diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index b04a6843..ad10ea1a 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -30,6 +30,10 @@ urlpatterns = [ path('employees//', views.EmployeeRUDView.as_view(), name='employees-rud'), path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'), path('types//', views.EstablishmentTypeRUDView.as_view(), name='type-rud'), + path('types/attach-tag-category/', views.EstablishmentTypeAttachTagCategoryView.as_view(), + name='type-attach-tag-category'), path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), + # path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), + # name='subtype-attach-tag-category'), ] \ No newline at end of file diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 32ee2805..7d0949be 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,8 +1,9 @@ """Establishment app views.""" from django.shortcuts import get_object_or_404 -from rest_framework import generics +from rest_framework import generics, status from establishment import models, serializers +from rest_framework.response import Response from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer @@ -55,7 +56,7 @@ class EstablishmentScheduleCreateView(generics.CreateAPIView): class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.ListAPIView): """View for establishment tag categories.""" - serializer_class = serializers.EstablishmentTagCategoryListSerializer + serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer pagination_class = None def get_object(self): @@ -81,6 +82,31 @@ class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.ListAPI return establishment.establishment_type.tag_categories.all() +class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): + """Attach tag category to establishment type.""" + serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer + + def get_queryset(self): + """Override get_queryset method.""" + return models.EstablishmentTypeTagCategory.objects.with_base_related() + + def post(self, request, *args, **kwargs): + """Overridden post-method.""" + super(EstablishmentTypeAttachTagCategoryView, self).post(request) + return Response(status=status.HTTP_200_OK) + + +# class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): +# """Attach tag category to establishment subtype.""" +# queryset = models.EstablishmentSubTypeTagCategory.objects.all() +# serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer +# +# def post(self, request, *args, **kwargs): +# """Overridden post-method.""" +# super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) +# return Response(status=status.HTTP_200_OK) + + class MenuListCreateView(generics.ListCreateAPIView): """Menu list create view.""" serializer_class = serializers.MenuSerializers From ddb3eec6790cad55810233d948c1ac0db0e80236 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 11 Oct 2019 15:41:31 +0300 Subject: [PATCH 08/25] finished endpoint to get tags by establishment type and subtype --- apps/establishment/admin.py | 9 +- .../0035_establishmentsubtypetagcategory.py | 27 +++ apps/establishment/models.py | 43 ++--- apps/establishment/serializers/back.py | 6 +- apps/establishment/serializers/common.py | 170 ++++++++++-------- apps/establishment/urls/back.py | 6 +- apps/establishment/views/back.py | 45 +++-- apps/establishment/views/web.py | 2 +- 8 files changed, 185 insertions(+), 123 deletions(-) create mode 100644 apps/establishment/migrations/0035_establishmentsubtypetagcategory.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index a40475b0..1f200f41 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -82,10 +82,15 @@ class MenuAdmin(admin.ModelAdmin): @admin.register(models.EstablishmentTypeTagCategory) -class EstablishmentTypeTagCategory(admin.ModelAdmin): +class EstablishmentTypeTagCategoryAdmin(admin.ModelAdmin): + """EstablishmentTypeTagCategory admin.""" + + +@admin.register(models.EstablishmentSubTypeTagCategory) +class EstablishmentSubTypeTagCategoryAdmin(admin.ModelAdmin): """EstablishmentTypeTagCategory admin.""" @admin.register(models.EstablishmentTag) -class EstablishmentTag(admin.ModelAdmin): +class EstablishmentTagAdmin(admin.ModelAdmin): """EstablishmentTag admin.""" diff --git a/apps/establishment/migrations/0035_establishmentsubtypetagcategory.py b/apps/establishment/migrations/0035_establishmentsubtypetagcategory.py new file mode 100644 index 00000000..6a85fca7 --- /dev/null +++ b/apps/establishment/migrations/0035_establishmentsubtypetagcategory.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2.4 on 2019-10-11 10:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0002_auto_20191009_1408'), + ('establishment', '0034_merge_20191009_1457'), + ] + + operations = [ + migrations.CreateModel( + name='EstablishmentSubTypeTagCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('establishment_subtype', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tag_categories', to='establishment.EstablishmentSubType', verbose_name='establishment subtype')), + ('tag_category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='est_subtype_tag_categories', to='tag.TagCategory', verbose_name='tag category')), + ], + options={ + 'verbose_name': 'establishment subtype tag categories', + 'verbose_name_plural': 'establishment subtype tag categories', + }, + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index c248ca5d..39b750fa 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -589,7 +589,6 @@ class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): def with_base_related(self): """Return with related relations.""" - # return self.select_related('tags', 'establishment_type') return self.select_related('establishment_type', 'tag_category') @@ -610,22 +609,26 @@ class EstablishmentTypeTagCategory(models.Model): verbose_name_plural = _('establishment type tag categories') -# class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet): -# """QuerySet for tag categories based on establishment subtype.""" -# -# -# class EstablishmentSubTypeTagCategory(models.Model): -# """Tag categories based on establishment subtype.""" -# establishment_subtype = models.ForeignKey(EstablishmentSubType, -# on_delete=models.CASCADE, -# related_name='tag_categories', -# verbose_name=_('establishment subtype')) -# tag_category = models.ForeignKey('tag.TagCategory', -# on_delete=models.CASCADE, -# related_name='est_subtype_tag_categories', -# verbose_name=_('tag category')) -# objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager() -# -# class Meta: -# verbose_name = _('establishment subtype tag categories') -# verbose_name_plural = _('establishment subtype tag categories') +class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet): + """QuerySet for tag categories based on establishment subtype.""" + + def with_base_related(self): + """Return queryset with base related.""" + return self.select_related('establishment_subtype', 'tag_category') + + +class EstablishmentSubTypeTagCategory(models.Model): + """Tag categories based on establishment subtype.""" + establishment_subtype = models.ForeignKey(EstablishmentSubType, + on_delete=models.CASCADE, + related_name='tag_categories', + verbose_name=_('establishment subtype')) + tag_category = models.ForeignKey('tag.TagCategory', + on_delete=models.CASCADE, + related_name='est_subtype_tag_categories', + verbose_name=_('tag category')) + objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager() + + class Meta: + verbose_name = _('establishment subtype tag categories') + verbose_name_plural = _('establishment subtype tag categories') diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 33d2e812..e164b44a 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -4,7 +4,7 @@ from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, ContactPhonesSerializer, SocialNetworkRelatedSerializers, - EstablishmentTypeSerializer) + EstablishmentTypeBaseSerializer) from main.models import Currency from utils.decorators import with_base_attributes @@ -20,7 +20,7 @@ class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): emails = ContactEmailsSerializer(read_only=True, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=True, many=True, ) slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) - type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) + type = EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True) class Meta: model = models.Establishment @@ -54,7 +54,7 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer): phones = ContactPhonesSerializer(read_only=False, many=True, ) emails = ContactEmailsSerializer(read_only=False, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=False, many=True, ) - type = EstablishmentTypeSerializer(source='establishment_type') + type = EstablishmentTypeBaseSerializer(source='establishment_type') class Meta: model = models.Establishment diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index ef21e4fb..eec51466 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -89,6 +89,57 @@ class MenuRUDSerializers(ProjectModelSerializer): ] +class ReviewSerializer(serializers.ModelSerializer): + """Serializer for model Review.""" + text_translated = serializers.CharField(read_only=True) + + class Meta: + """Meta class.""" + model = review_models.Review + fields = ( + 'text_translated', + ) + + +class EstablishmentTypeBaseSerializer(serializers.ModelSerializer): + """Serializer for EstablishmentType model.""" + name_translated = TranslatedField() + + class Meta: + """Meta class.""" + model = models.EstablishmentType + fields = [ + 'id', + 'name', + 'name_translated', + 'use_subtypes' + ] + extra_kwargs = { + 'name': {'write_only': True}, + 'use_subtypes': {'write_only': True}, + } + + +class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer): + """Serializer for EstablishmentSubType models.""" + + name_translated = TranslatedField() + + class Meta: + """Meta class.""" + model = models.EstablishmentSubType + fields = [ + 'id', + 'name', + 'name_translated', + 'establishment_type' + ] + extra_kwargs = { + 'name': {'write_only': True}, + 'establishment_type': {'write_only': True} + } + + class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): """Serializer for intermediate model EstablishmentTypeTagCategories.""" id = serializers.IntegerField(source='tag_category.id', read_only=True) @@ -119,71 +170,62 @@ class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): return attrs -class EstablishmentTypeSerializer(serializers.ModelSerializer): - """Serializer for EstablishmentType model.""" - - name_translated = TranslatedField() +class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): + """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" + id = serializers.IntegerField(source='tag_category.id', read_only=True) + label_translated = TranslatedField(source='tag_category.label_translated') + tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) class Meta: """Meta class.""" - - model = models.EstablishmentType - fields = ('id', 'name', 'name_translated') + model = models.EstablishmentSubTypeTagCategory + fields = [ + 'id', + 'label_translated', + 'tags', + 'establishment_subtype', + 'tag_category', + ] extra_kwargs = { - 'name': {'write_only': True} + 'establishment_subtype': {'write_only': True}, + 'tag_category': {'write_only': True}, } + def validate(self, attrs): + """Override validate method.""" + if models.EstablishmentTypeTagCategory.objects.filter( + establishment_type=attrs.get('establishment_type'), + tag_category=attrs.get('tag_category')).exists(): + raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) + return attrs -class EstablishmentSubTypeSerializer(serializers.ModelSerializer): - """Serializer for EstablishmentSubType models.""" - name_translated = TranslatedField() +class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer): + """Extended serializer for EstablishmentSubType model with tags.""" + tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True) - class Meta: + class Meta(EstablishmentSubTypeBaseSerializer.Meta): + """Meta class""" + fields = [ + 'id', + 'name_translated', + 'tag_categories' + ] + + +class EstablishmentTagsByType(EstablishmentTypeBaseSerializer): + """Tags by establishment type""" + tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True) + subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set') + + class Meta(EstablishmentTypeBaseSerializer.Meta): """Meta class.""" - - model = models.EstablishmentSubType - fields = ('id', 'name', 'name_translated', 'establishment_type') - extra_kwargs = { - 'name': {'write_only': True}, - 'establishment_type': {'write_only': True} - } - - -# class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): -# """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" -# -# class Meta: -# """Meta class.""" -# model = models.EstablishmentSubTypeTagCategory -# fields = [ -# 'establishment_subtype', -# 'tag_category', -# ] -# extra_kwargs = { -# 'establishment_subtype': {'write_only': True}, -# 'tag_category': {'write_only': True}, -# } -# -# def validate(self, attrs): -# """Override validate method.""" -# if models.EstablishmentSubTypeTagCategory.objects.filter( -# establishment_type=attrs.get('establishment_subtype'), -# tag_category=attrs.get('tag_category')).exists(): -# raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) -# return attrs - - -class ReviewSerializer(serializers.ModelSerializer): - """Serializer for model Review.""" - text_translated = serializers.CharField(read_only=True) - - class Meta: - """Meta class.""" - model = review_models.Review - fields = ( - 'text_translated', - ) + fields = [ + 'id', + 'name_translated', + 'tag_categories', + 'subtypes', + ] class EstablishmentEmployeeSerializer(serializers.ModelSerializer): @@ -202,19 +244,6 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): fields = ('id', 'name', 'position_translated', 'awards', 'priority') -class EstablishmentCategoryTagListSerializer(serializers.ModelSerializer): - """Serializer for establishment category tags.""" - label_translated = TranslatedField() - - class Meta: - """Meta class.""" - model = tag_models.TagCategory - fields = [ - 'id', - 'label_translated', - ] - - class EstablishmentTagSerializer(serializers.ModelSerializer): """Serializer for intermediate model EstablishmentTag.""" id = serializers.IntegerField(source='tag.id') @@ -262,8 +291,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer): description_translated = TranslatedField() image = serializers.URLField(source='image_url') - type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) - subtypes = EstablishmentSubTypeSerializer(many=True, source='establishment_subtypes') + type = EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True) + subtypes = EstablishmentSubTypeBaseSerializer(many=True, source='establishment_subtypes') awards = AwardSerializer(many=True) schedule = ScheduleRUDSerializer(many=True, allow_null=True) phones = ContactPhonesSerializer(read_only=True, many=True) @@ -396,3 +425,4 @@ class EstablishmentFavoritesCreateSerializer(serializers.ModelSerializer): 'content_object': validated_data.pop('establishment') }) return super().create(validated_data) + diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index ad10ea1a..e0489783 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -14,7 +14,7 @@ urlpatterns = [ name='schedule-rud'), path('/schedule/', views.EstablishmentScheduleCreateView.as_view(), name='schedule-create'), - path('/tags/categories/', views.EstablishmentTagCategoryListView.as_view(), + path('/tags/', views.EstablishmentTagCategoryListView.as_view(), name='tag-category-list'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), @@ -34,6 +34,6 @@ urlpatterns = [ name='type-attach-tag-category'), path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), - # path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), - # name='subtype-attach-tag-category'), + path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), + name='subtype-attach-tag-category'), ] \ No newline at end of file diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 7d0949be..84855982 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -54,9 +54,9 @@ class EstablishmentScheduleCreateView(generics.CreateAPIView): serializer_class = ScheduleCreateSerializer -class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.ListAPIView): +class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.RetrieveAPIView): """View for establishment tag categories.""" - serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer + serializer_class = serializers.EstablishmentTagsByType pagination_class = None def get_object(self): @@ -74,12 +74,7 @@ class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.ListAPI # May raise a permission denied self.check_object_permissions(self.request, obj) - return obj - - def get_queryset(self): - """Overridden get_queryset method.""" - establishment = self.get_object() - return establishment.establishment_type.tag_categories.all() + return obj.establishment_type class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): @@ -96,17 +91,6 @@ class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): return Response(status=status.HTTP_200_OK) -# class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): -# """Attach tag category to establishment subtype.""" -# queryset = models.EstablishmentSubTypeTagCategory.objects.all() -# serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer -# -# def post(self, request, *args, **kwargs): -# """Overridden post-method.""" -# super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) -# return Response(status=status.HTTP_200_OK) - - class MenuListCreateView(generics.ListCreateAPIView): """Menu list create view.""" serializer_class = serializers.MenuSerializers @@ -186,31 +170,44 @@ class EmployeeRUDView(generics.RetrieveUpdateDestroyAPIView): class EstablishmentTypeListCreateView(generics.ListCreateAPIView): """Establishment type list/create view.""" - serializer_class = serializers.EstablishmentTypeSerializer + serializer_class = serializers.EstablishmentTypeBaseSerializer queryset = models.EstablishmentType.objects.all() pagination_class = None class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView): """Establishment type retrieve/update/destroy view.""" - serializer_class = serializers.EstablishmentTypeSerializer + serializer_class = serializers.EstablishmentTypeBaseSerializer queryset = models.EstablishmentType.objects.all() class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView): """Establishment subtype list/create view.""" - serializer_class = serializers.EstablishmentSubTypeSerializer + serializer_class = serializers.EstablishmentSubTypeBaseSerializer queryset = models.EstablishmentSubType.objects.all() pagination_class = None class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView): """Establishment subtype retrieve/update/destroy view.""" - serializer_class = serializers.EstablishmentSubTypeSerializer + serializer_class = serializers.EstablishmentSubTypeBaseSerializer queryset = models.EstablishmentSubType.objects.all() -# todo: next task +class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): + """Attach tag category to establishment subtype.""" + serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer + + def get_queryset(self): + """Override get_queryset method.""" + return models.EstablishmentSubTypeTagCategory.objects.with_base_related() + + def post(self, request, *args, **kwargs): + """Overridden post-method.""" + super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) + return Response(status=status.HTTP_200_OK) + + # class EstablishmentTagListCreateView(generics.CreateAPIView): # """Establishment tag list/create view.""" # serializer_class = serializers.EstablishmentTagCategoryListCreateSerializer diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index b4ef4f13..f164ec73 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -84,7 +84,7 @@ class EstablishmentTypeListView(generics.ListAPIView): """Resource for getting a list of establishment types.""" permission_classes = (permissions.AllowAny,) - serializer_class = serializers.EstablishmentTypeSerializer + serializer_class = serializers.EstablishmentTypeBaseSerializer queryset = models.EstablishmentType.objects.all() From cb762ce746dbfa20cb3f9c5afafee26c3dbbde51 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 11 Oct 2019 18:26:13 +0300 Subject: [PATCH 09/25] added param to attr for Establoishment model and small refactoring, boost queries --- .../migrations/0036_auto_20191011_1356.py | 18 ++++ apps/establishment/models.py | 7 ++ apps/establishment/serializers/back.py | 98 ++++++++++++++++++- apps/establishment/serializers/common.py | 59 ----------- apps/establishment/urls/back.py | 5 +- apps/establishment/views/back.py | 11 +-- 6 files changed, 130 insertions(+), 68 deletions(-) create mode 100644 apps/establishment/migrations/0036_auto_20191011_1356.py diff --git a/apps/establishment/migrations/0036_auto_20191011_1356.py b/apps/establishment/migrations/0036_auto_20191011_1356.py new file mode 100644 index 00000000..c2eb2e4e --- /dev/null +++ b/apps/establishment/migrations/0036_auto_20191011_1356.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-10-11 13:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0035_establishmentsubtypetagcategory'), + ] + + operations = [ + migrations.AlterField( + model_name='establishment', + name='establishment_subtypes', + field=models.ManyToManyField(blank=True, related_name='subtype_establishment', to='establishment.EstablishmentSubType', verbose_name='subtype'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 39b750fa..169590ff 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -23,6 +23,10 @@ from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, TranslatedFieldsMixin, BaseAttributes) +class EstablishmentTypeQuerySet(models.QuerySet): + """QuerySet for model EstablishmentType.""" + + # todo: establishment type&subtypes check class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): """Establishment type model.""" @@ -82,6 +86,8 @@ class EstablishmentQuerySet(models.QuerySet): EstablishmentTag.objects.select_related('tag')), models.Prefetch('establishment_type__tag_categories', EstablishmentTypeTagCategory.objects.select_related('tag_category')), + models.Prefetch('establishment_type__establishmentsubtype_set', + EstablishmentSubType.objects.prefetch_related('tag_categories')), ) def with_extended_related(self): @@ -257,6 +263,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): on_delete=models.PROTECT, verbose_name=_('type')) establishment_subtypes = models.ManyToManyField(EstablishmentSubType, + blank=True, related_name='subtype_establishment', verbose_name=_('subtype')) address = models.ForeignKey(Address, blank=True, null=True, default=None, diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index e164b44a..21f63e17 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,12 +1,16 @@ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, ContactPhonesSerializer, SocialNetworkRelatedSerializers, - EstablishmentTypeBaseSerializer) + EstablishmentTypeBaseSerializer, EstablishmentSubTypeBaseSerializer, + EstablishmentTypeTagCategoryBaseSerializer) from main.models import Currency +from tag.serializers import TagBaseSerializer from utils.decorators import with_base_attributes +from utils.serializers import TranslatedField class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): @@ -141,3 +145,95 @@ class EmployeeBackSerializers(serializers.ModelSerializer): 'name' ] + +class EstablishmentTagCreateSerializer(serializers.ModelSerializer): + """Serializer for model EstablishmentTag.""" + class Meta: + model = models.EstablishmentTag + fields = [ + 'tag', + 'establishment' + ] + extra_kwargs = { + 'tag': {'write_only': True}, + 'establishment': {'write_only': True}, + } + + def validate(self, attrs): + """Validate method.""" + establishment = attrs.get('establishment') + tag = attrs.get('tag') + + # Check if tag is already added to establishment. + if establishment.tags.filter(tag=tag).exists(): + raise serializers.ValidationError(detail={'detail': _('Tag is already added.')}) + + # Сhecking tag availability for establishment type. + if not establishment.establishment_type.use_subtypes: + qs = establishment.establishment_type.tag_categories.filter(tag_category=tag.category) + else: + # Сhecking tag availability for establishment subtype. + qs = establishment.establishment_type.tag_categories.filter( + establishmentsubtype_set__tag_category=tag.category) + if not qs.exists(): + raise serializers.ValidationError( + detail={'detail': _('Tag is not available for this establishment type|subtype.')}) + return attrs + + +class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): + """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" + id = serializers.IntegerField(source='tag_category.id', read_only=True) + label_translated = TranslatedField(source='tag_category.label_translated') + tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) + + class Meta: + """Meta class.""" + model = models.EstablishmentSubTypeTagCategory + fields = [ + 'id', + 'label_translated', + 'tags', + 'establishment_subtype', + 'tag_category', + ] + extra_kwargs = { + 'establishment_subtype': {'write_only': True}, + 'tag_category': {'write_only': True}, + } + + def validate(self, attrs): + """Override validate method.""" + if models.EstablishmentTypeTagCategory.objects.filter( + establishment_type=attrs.get('establishment_type'), + tag_category=attrs.get('tag_category')).exists(): + raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) + return attrs + + +class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer): + """Extended serializer for EstablishmentSubType model with tags.""" + tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True) + + class Meta(EstablishmentSubTypeBaseSerializer.Meta): + """Meta class""" + fields = [ + 'id', + 'name_translated', + 'tag_categories' + ] + + +class EstablishmentTagsByType(EstablishmentTypeBaseSerializer): + """Tags by establishment type""" + tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True) + subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set') + + class Meta(EstablishmentTypeBaseSerializer.Meta): + """Meta class.""" + fields = [ + 'id', + 'name_translated', + 'tag_categories', + 'subtypes', + ] diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index eec51466..1789da31 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -9,7 +9,6 @@ from favorites.models import Favorites from location.serializers import AddressBaseSerializer from main.serializers import AwardSerializer, CurrencySerializer from review import models as review_models -from tag import models as tag_models from tag.serializers import TagBaseSerializer from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions @@ -170,64 +169,6 @@ class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): return attrs -class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): - """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" - id = serializers.IntegerField(source='tag_category.id', read_only=True) - label_translated = TranslatedField(source='tag_category.label_translated') - tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) - - class Meta: - """Meta class.""" - model = models.EstablishmentSubTypeTagCategory - fields = [ - 'id', - 'label_translated', - 'tags', - 'establishment_subtype', - 'tag_category', - ] - extra_kwargs = { - 'establishment_subtype': {'write_only': True}, - 'tag_category': {'write_only': True}, - } - - def validate(self, attrs): - """Override validate method.""" - if models.EstablishmentTypeTagCategory.objects.filter( - establishment_type=attrs.get('establishment_type'), - tag_category=attrs.get('tag_category')).exists(): - raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) - return attrs - - -class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer): - """Extended serializer for EstablishmentSubType model with tags.""" - tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True) - - class Meta(EstablishmentSubTypeBaseSerializer.Meta): - """Meta class""" - fields = [ - 'id', - 'name_translated', - 'tag_categories' - ] - - -class EstablishmentTagsByType(EstablishmentTypeBaseSerializer): - """Tags by establishment type""" - tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True) - subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set') - - class Meta(EstablishmentTypeBaseSerializer.Meta): - """Meta class.""" - fields = [ - 'id', - 'name_translated', - 'tag_categories', - 'subtypes', - ] - - class EstablishmentEmployeeSerializer(serializers.ModelSerializer): """Serializer for actual employees.""" diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index e0489783..c21aecc8 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -14,8 +14,9 @@ urlpatterns = [ name='schedule-rud'), path('/schedule/', views.EstablishmentScheduleCreateView.as_view(), name='schedule-create'), - path('/tags/', views.EstablishmentTagCategoryListView.as_view(), + path('/type/tags/', views.EstablishmentTagCategoryListView.as_view(), name='tag-category-list'), + path('attach-tag/', views.EstablishmentTagCreateView.as_view(), name='attach-tag'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), @@ -36,4 +37,4 @@ urlpatterns = [ path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), name='subtype-attach-tag-category'), -] \ No newline at end of file +] diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 84855982..fd61485d 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -91,6 +91,11 @@ class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): return Response(status=status.HTTP_200_OK) +class EstablishmentTagCreateView(EstablishmentMixinViews, generics.CreateAPIView): + """Attach tag to establishment.""" + serializer_class = serializers.EstablishmentTagCreateSerializer + + class MenuListCreateView(generics.ListCreateAPIView): """Menu list create view.""" serializer_class = serializers.MenuSerializers @@ -206,9 +211,3 @@ class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): """Overridden post-method.""" super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) return Response(status=status.HTTP_200_OK) - - -# class EstablishmentTagListCreateView(generics.CreateAPIView): -# """Establishment tag list/create view.""" -# serializer_class = serializers.EstablishmentTagCategoryListCreateSerializer -# queryset = models.EstablishmentTag.objects.all() From 47993a7155c8a682c4ec9132ff32dcb273416aef Mon Sep 17 00:00:00 2001 From: Anatoly Date: Mon, 14 Oct 2019 10:22:17 +0300 Subject: [PATCH 10/25] added endpoint ot get list of tag categories with tags by establishment type --- apps/establishment/urls/back.py | 1 + apps/establishment/views/back.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index c21aecc8..f1afe1df 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -30,6 +30,7 @@ urlpatterns = [ path('employees/', views.EmployeeListCreateView.as_view(), name='employees'), path('employees//', views.EmployeeRUDView.as_view(), name='employees-rud'), path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'), + path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), path('types//', views.EstablishmentTypeRUDView.as_view(), name='type-rud'), path('types/attach-tag-category/', views.EstablishmentTypeAttachTagCategoryView.as_view(), name='type-attach-tag-category'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index fd61485d..09bf2492 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -186,6 +186,13 @@ class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = models.EstablishmentType.objects.all() +class EstablishmentTypeTagListView(generics.ListAPIView): + """List of tags with categories by establishment type.""" + serializer_class = serializers.EstablishmentTagsByType + queryset = models.EstablishmentType.objects.all() + pagination_class = None + + class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView): """Establishment subtype list/create view.""" serializer_class = serializers.EstablishmentSubTypeBaseSerializer From 9e237d465711b6f890ee878266828acf9a6b3394 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Mon, 14 Oct 2019 11:40:03 +0300 Subject: [PATCH 11/25] removed endpoint to display a list of tags by establishment id, added instead filter to filter tags by establishment id --- apps/account/views/common.py | 1 + apps/establishment/filters.py | 14 ++++++++++++++ apps/establishment/urls/back.py | 2 -- apps/establishment/views/back.py | 28 ++++------------------------ 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/apps/account/views/common.py b/apps/account/views/common.py index cb0d84d7..0a9a4d98 100644 --- a/apps/account/views/common.py +++ b/apps/account/views/common.py @@ -91,6 +91,7 @@ class ConfirmEmailView(JWTGenericViewMixin): else: raise utils_exceptions.UserNotFoundError() + class ConfirmPasswordView(JWTGenericViewMixin): """View for applying newly set password""" diff --git a/apps/establishment/filters.py b/apps/establishment/filters.py index 51b207dc..13d951b6 100644 --- a/apps/establishment/filters.py +++ b/apps/establishment/filters.py @@ -26,3 +26,17 @@ class EstablishmentFilter(filters.FilterSet): if value not in EMPTY_VALUES: return queryset.search(value, locale=self.request.locale) return queryset + + +class EstablishmentTypeTagFilter(filters.FilterSet): + """Establishment tag filter set.""" + + type_id = filters.NumberFilter(field_name='id') + + class Meta: + """Meta class.""" + + model = models.EstablishmentType + fields = ( + 'type_id', + ) diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index f1afe1df..3db81dce 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -14,8 +14,6 @@ urlpatterns = [ name='schedule-rud'), path('/schedule/', views.EstablishmentScheduleCreateView.as_view(), name='schedule-create'), - path('/type/tags/', views.EstablishmentTagCategoryListView.as_view(), - name='tag-category-list'), path('attach-tag/', views.EstablishmentTagCreateView.as_view(), name='attach-tag'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 09bf2492..a5e2ff47 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,10 +1,11 @@ """Establishment app views.""" from django.shortcuts import get_object_or_404 -from rest_framework import generics, status +from rest_framework import generics, status, permissions from establishment import models, serializers from rest_framework.response import Response from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer +from establishment.filters import EstablishmentTypeTagFilter class EstablishmentMixinViews: @@ -54,29 +55,6 @@ class EstablishmentScheduleCreateView(generics.CreateAPIView): serializer_class = ScheduleCreateSerializer -class EstablishmentTagCategoryListView(EstablishmentMixinViews, generics.RetrieveAPIView): - """View for establishment tag categories.""" - serializer_class = serializers.EstablishmentTagsByType - pagination_class = None - - def get_object(self): - """ - Returns the object the view is displaying. - """ - queryset = super(EstablishmentTagCategoryListView, self).get_queryset() - - # Perform the lookup filtering. - lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field - - filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} - obj = get_object_or_404(queryset, **filter_kwargs) - - # May raise a permission denied - self.check_object_permissions(self.request, obj) - - return obj.establishment_type - - class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): """Attach tag category to establishment type.""" serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer @@ -190,6 +168,8 @@ class EstablishmentTypeTagListView(generics.ListAPIView): """List of tags with categories by establishment type.""" serializer_class = serializers.EstablishmentTagsByType queryset = models.EstablishmentType.objects.all() + filter_class = EstablishmentTypeTagFilter + permission_classes = (permissions.AllowAny, ) pagination_class = None From 469f7bdf4cb506c8a317e3a127a96bff73cdc0e1 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Mon, 14 Oct 2019 12:24:26 +0300 Subject: [PATCH 12/25] added prefetch select related --- apps/establishment/models.py | 15 +++++++++++++++ apps/establishment/views/back.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 77992f9d..195f029d 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -16,6 +16,7 @@ from phonenumber_field.modelfields import PhoneNumberField from collection.models import Collection from location.models import Address from main.models import Award +from tag.models import Tag, TagCategory from review.models import Review from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, TranslatedFieldsMixin, BaseAttributes) @@ -24,6 +25,18 @@ from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, class EstablishmentTypeQuerySet(models.QuerySet): """QuerySet for model EstablishmentType.""" + def with_base_related(self): + """Return QuerySet with base related.""" + return self.prefetch_related( + models.Prefetch('tag_categories', + EstablishmentTypeTagCategory.objects.select_related('tag_category')), + models.Prefetch('establishmentsubtype_set', + EstablishmentSubType.objects.prefetch_related( + models.Prefetch( + 'tag_categories', + EstablishmentSubTypeTagCategory.objects.select_related('tag_category')))) + ) + # todo: establishment type&subtypes check class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): @@ -35,6 +48,8 @@ class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): help_text='{"en-GB":"some text"}') use_subtypes = models.BooleanField(_('Use subtypes'), default=True) + objects = EstablishmentTypeQuerySet.as_manager() + class Meta: """Meta class.""" diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index a5e2ff47..543dbd3e 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -167,7 +167,7 @@ class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView): class EstablishmentTypeTagListView(generics.ListAPIView): """List of tags with categories by establishment type.""" serializer_class = serializers.EstablishmentTagsByType - queryset = models.EstablishmentType.objects.all() + queryset = models.EstablishmentType.objects.with_base_related() filter_class = EstablishmentTypeTagFilter permission_classes = (permissions.AllowAny, ) pagination_class = None From 1764cfc08b17f6c36f5cdd85d87a8b9487e2bb1f Mon Sep 17 00:00:00 2001 From: Anatoly Date: Tue, 15 Oct 2019 12:52:21 +0300 Subject: [PATCH 13/25] added urlpath to get establishment tags to all platform --- apps/establishment/urls/common.py | 1 + project/urls/back.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 5d7df146..18b768c0 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -7,6 +7,7 @@ app_name = 'establishment' urlpatterns = [ path('', views.EstablishmentListView.as_view(), name='list'), + path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), name='recent-reviews'), path('slug//', views.EstablishmentRetrieveView.as_view(), name='detail'), diff --git a/project/urls/back.py b/project/urls/back.py index 7cfcd038..eb049b9c 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -7,7 +7,7 @@ urlpatterns = [ path('establishments/', include('establishment.urls.back')), path('location/', include('location.urls.back')), path('news/', include('news.urls.back')), - path('tags/', include(('tag.urls', 'tag'), namespace='tag')) + path('tags/', include(('tag.urls', 'tag'), namespace='tag')), path('account/', include('account.urls.back')), path('comment/', include('comment.urls.back')), ] From 60cdec99e02a9b0cbab04110517cebe4cfe80772 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 17:17:03 +0300 Subject: [PATCH 14/25] refactor tags --- apps/establishment/admin.py | 28 +-- .../migrations/0037_auto_20191015_1404.py | 54 +++++ apps/establishment/models.py | 202 ++++++++++-------- apps/establishment/serializers/back.py | 182 ++++++++-------- apps/establishment/serializers/common.py | 84 ++++---- apps/establishment/urls/back.py | 12 +- apps/establishment/urls/common.py | 2 +- apps/establishment/views/back.py | 70 +++--- apps/search_indexes/documents/news.py | 18 +- apps/tag/filters.py | 48 +++++ apps/tag/models.py | 12 +- apps/tag/serializers.py | 46 ++-- apps/tag/urls/__init__.py | 0 apps/tag/{urls.py => urls/back.py} | 10 +- apps/tag/urls/web.py | 16 ++ apps/tag/views.py | 28 ++- project/settings/base.py | 2 +- project/urls/back.py | 2 +- project/urls/web.py | 1 + 19 files changed, 494 insertions(+), 323 deletions(-) create mode 100644 apps/establishment/migrations/0037_auto_20191015_1404.py create mode 100644 apps/tag/filters.py create mode 100644 apps/tag/urls/__init__.py rename apps/tag/{urls.py => urls/back.py} (53%) create mode 100644 apps/tag/urls/web.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index 1f200f41..8a5e57de 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -80,17 +80,17 @@ class MenuAdmin(admin.ModelAdmin): category_translated.short_description = _('category') - -@admin.register(models.EstablishmentTypeTagCategory) -class EstablishmentTypeTagCategoryAdmin(admin.ModelAdmin): - """EstablishmentTypeTagCategory admin.""" - - -@admin.register(models.EstablishmentSubTypeTagCategory) -class EstablishmentSubTypeTagCategoryAdmin(admin.ModelAdmin): - """EstablishmentTypeTagCategory admin.""" - - -@admin.register(models.EstablishmentTag) -class EstablishmentTagAdmin(admin.ModelAdmin): - """EstablishmentTag admin.""" +# +# @admin.register(models.EstablishmentTypeTagCategory) +# class EstablishmentTypeTagCategoryAdmin(admin.ModelAdmin): +# """EstablishmentTypeTagCategory admin.""" +# +# +# @admin.register(models.EstablishmentSubTypeTagCategory) +# class EstablishmentSubTypeTagCategoryAdmin(admin.ModelAdmin): +# """EstablishmentTypeTagCategory admin.""" +# +# +# @admin.register(models.EstablishmentTag) +# class EstablishmentTagAdmin(admin.ModelAdmin): +# """EstablishmentTag admin.""" diff --git a/apps/establishment/migrations/0037_auto_20191015_1404.py b/apps/establishment/migrations/0037_auto_20191015_1404.py new file mode 100644 index 00000000..971970e2 --- /dev/null +++ b/apps/establishment/migrations/0037_auto_20191015_1404.py @@ -0,0 +1,54 @@ +# Generated by Django 2.2.4 on 2019-10-15 14:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0002_auto_20191009_1408'), + ('establishment', '0036_auto_20191011_1356'), + ] + + operations = [ + migrations.RemoveField( + model_name='establishmenttag', + name='establishment', + ), + migrations.RemoveField( + model_name='establishmenttag', + name='tag', + ), + migrations.RemoveField( + model_name='establishmenttypetagcategory', + name='establishment_type', + ), + migrations.RemoveField( + model_name='establishmenttypetagcategory', + name='tag_category', + ), + migrations.AddField( + model_name='establishment', + name='tags', + field=models.ManyToManyField(related_name='establishments', to='tag.Tag', verbose_name='Tag'), + ), + migrations.AddField( + model_name='establishmentsubtype', + name='tag_categories', + field=models.ManyToManyField(related_name='establishment_subtypes', to='tag.TagCategory', verbose_name='Tag'), + ), + migrations.AddField( + model_name='establishmenttype', + name='tag_categories', + field=models.ManyToManyField(related_name='establishment_types', to='tag.TagCategory', verbose_name='Tag'), + ), + migrations.DeleteModel( + name='EstablishmentSubTypeTagCategory', + ), + migrations.DeleteModel( + name='EstablishmentTag', + ), + migrations.DeleteModel( + name='EstablishmentTypeTagCategory', + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 195f029d..14d7e02b 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -27,15 +27,16 @@ class EstablishmentTypeQuerySet(models.QuerySet): def with_base_related(self): """Return QuerySet with base related.""" - return self.prefetch_related( - models.Prefetch('tag_categories', - EstablishmentTypeTagCategory.objects.select_related('tag_category')), - models.Prefetch('establishmentsubtype_set', - EstablishmentSubType.objects.prefetch_related( - models.Prefetch( - 'tag_categories', - EstablishmentSubTypeTagCategory.objects.select_related('tag_category')))) - ) + return self + # return self.prefetch_related( + # models.Prefetch('tag_categories', + # EstablishmentTypeTagCategory.objects.select_related('tag_category')), + # models.Prefetch('establishmentsubtype_set', + # EstablishmentSubType.objects.prefetch_related( + # models.Prefetch( + # 'tag_categories', + # EstablishmentSubTypeTagCategory.objects.select_related('tag_category')))) + # ) # todo: establishment type&subtypes check @@ -47,6 +48,9 @@ class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), help_text='{"en-GB":"some text"}') use_subtypes = models.BooleanField(_('Use subtypes'), default=True) + tag_categories = models.ManyToManyField('tag.TagCategory', + related_name='establishment_types', + verbose_name=_('Tag')) objects = EstablishmentTypeQuerySet.as_manager() @@ -75,6 +79,9 @@ class EstablishmentSubType(ProjectBaseMixin, TranslatedFieldsMixin): establishment_type = models.ForeignKey(EstablishmentType, on_delete=models.CASCADE, verbose_name=_('Type')) + tag_categories = models.ManyToManyField('tag.TagCategory', + related_name='establishment_subtypes', + verbose_name=_('Tag')) objects = EstablishmentSubTypeManager() @@ -94,14 +101,15 @@ class EstablishmentQuerySet(models.QuerySet): def with_base_related(self): """Return qs with related objects.""" - return self.select_related('address', 'establishment_type').prefetch_related( - models.Prefetch('tags', - EstablishmentTag.objects.select_related('tag')), - models.Prefetch('establishment_type__tag_categories', - EstablishmentTypeTagCategory.objects.select_related('tag_category')), - models.Prefetch('establishment_type__establishmentsubtype_set', - EstablishmentSubType.objects.prefetch_related('tag_categories')), - ) + return self + # return self.select_related('address', 'establishment_type').prefetch_related( + # models.Prefetch('tags', + # EstablishmentTag.objects.select_related('tag')), + # models.Prefetch('establishment_type__tag_categories', + # EstablishmentTypeTagCategory.objects.select_related('tag_category')), + # models.Prefetch('establishment_type__establishmentsubtype_set', + # EstablishmentSubType.objects.prefetch_related('tag_categories')), + # ) def with_extended_related(self): return self.select_related('establishment_type').\ @@ -320,7 +328,11 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): verbose_name=_('Establishment slug'), editable=True) awards = generic.GenericRelation(to='main.Award', related_query_name='establishment') - tags = generic.GenericRelation(to='main.MetaDataContent') + # todo: remove after data merge + # tags = generic.GenericRelation(to='main.MetaDataContent') + tags = models.ManyToManyField('tag.Tag', related_name='establishments', + verbose_name=_('Tag')) + old_tags = generic.GenericRelation(to='main.MetaDataContent') reviews = generic.GenericRelation(to='review.Review') comments = generic.GenericRelation(to='comment.Comment') favorites = generic.GenericRelation(to='favorites.Favorites') @@ -575,81 +587,81 @@ class SocialNetwork(models.Model): def __str__(self): return self.title +# +# class EstablishmentTagQuerySet(models.QuerySet): +# """Establishment tag QuerySet.""" +# +# def by_country_code(self, code): +# """Return establishment tags by establishment country code.""" +# return self.filter(establishment__address__city__country__code=code) -class EstablishmentTagQuerySet(models.QuerySet): - """Establishment tag QuerySet.""" - - def by_country_code(self, code): - """Return establishment tags by establishment country code.""" - return self.filter(establishment__address__city__country__code=code) - - -class EstablishmentTag(models.Model): - """Establishment tag model.""" - tag = models.ForeignKey('tag.Tag', - on_delete=models.CASCADE, - related_name='tags', - verbose_name=_('tag')) - establishment = models.ForeignKey('establishment.Establishment', - on_delete=models.CASCADE, - related_name='tags', - verbose_name=_('establishment')) - objects = EstablishmentTagQuerySet.as_manager() - - class Meta: - verbose_name = _('establishment tag') - verbose_name_plural = _('establishment tags') - - -class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): - """EstablishmentTypeTagCategory QuerySet.""" - - def by_country_code(self, code): - """Return establishment tags by country code""" - return self.filter(tag_category__country__code=code) - - def with_base_related(self): - """Return with related relations.""" - return self.select_related('establishment_type', 'tag_category') - - -class EstablishmentTypeTagCategory(models.Model): - """Tag categories based on establishment type.""" - establishment_type = models.ForeignKey(EstablishmentType, - on_delete=models.CASCADE, - related_name='tag_categories', - verbose_name=_('establishment type')) - tag_category = models.ForeignKey('tag.TagCategory', - on_delete=models.CASCADE, - related_name='est_type_tag_categories', - verbose_name=_('tag category')) - objects = EstablishmentTypeTagCategoryQuerySet.as_manager() - - class Meta: - verbose_name = _('establishment type tag categories') - verbose_name_plural = _('establishment type tag categories') - - -class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet): - """QuerySet for tag categories based on establishment subtype.""" - - def with_base_related(self): - """Return queryset with base related.""" - return self.select_related('establishment_subtype', 'tag_category') - - -class EstablishmentSubTypeTagCategory(models.Model): - """Tag categories based on establishment subtype.""" - establishment_subtype = models.ForeignKey(EstablishmentSubType, - on_delete=models.CASCADE, - related_name='tag_categories', - verbose_name=_('establishment subtype')) - tag_category = models.ForeignKey('tag.TagCategory', - on_delete=models.CASCADE, - related_name='est_subtype_tag_categories', - verbose_name=_('tag category')) - objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager() - - class Meta: - verbose_name = _('establishment subtype tag categories') - verbose_name_plural = _('establishment subtype tag categories') +# +# class EstablishmentTag(models.Model): +# """Establishment tag model.""" +# tag = models.ForeignKey('tag.Tag', +# on_delete=models.CASCADE, +# related_name='tags', +# verbose_name=_('tag')) +# establishment = models.ForeignKey('establishment.Establishment', +# on_delete=models.CASCADE, +# related_name='tags', +# verbose_name=_('establishment')) +# objects = EstablishmentTagQuerySet.as_manager() +# +# class Meta: +# verbose_name = _('establishment tag') +# verbose_name_plural = _('establishment tags') +# +# +# class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): +# """EstablishmentTypeTagCategory QuerySet.""" +# +# def by_country_code(self, code): +# """Return establishment tags by country code""" +# return self.filter(tag_category__country__code=code) +# +# def with_base_related(self): +# """Return with related relations.""" +# return self.select_related('establishment_type', 'tag_category') +# +# +# class EstablishmentTypeTagCategory(models.Model): +# """Tag categories based on establishment type.""" +# establishment_type = models.ForeignKey(EstablishmentType, +# on_delete=models.CASCADE, +# related_name='tag_categories', +# verbose_name=_('establishment type')) +# tag_category = models.ForeignKey('tag.TagCategory', +# on_delete=models.CASCADE, +# related_name='est_type_tag_categories', +# verbose_name=_('tag category')) +# objects = EstablishmentTypeTagCategoryQuerySet.as_manager() +# +# class Meta: +# verbose_name = _('establishment type tag categories') +# verbose_name_plural = _('establishment type tag categories') +# +# +# class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet): +# """QuerySet for tag categories based on establishment subtype.""" +# +# def with_base_related(self): +# """Return queryset with base related.""" +# return self.select_related('establishment_subtype', 'tag_category') +# +# +# class EstablishmentSubTypeTagCategory(models.Model): +# """Tag categories based on establishment subtype.""" +# establishment_subtype = models.ForeignKey(EstablishmentSubType, +# on_delete=models.CASCADE, +# related_name='tag_categories', +# verbose_name=_('establishment subtype')) +# tag_category = models.ForeignKey('tag.TagCategory', +# on_delete=models.CASCADE, +# related_name='est_subtype_tag_categories', +# verbose_name=_('tag category')) +# objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager() +# +# class Meta: +# verbose_name = _('establishment subtype tag categories') +# verbose_name_plural = _('establishment subtype tag categories') diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 21f63e17..dca25763 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -5,8 +5,8 @@ from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, ContactPhonesSerializer, SocialNetworkRelatedSerializers, - EstablishmentTypeBaseSerializer, EstablishmentSubTypeBaseSerializer, - EstablishmentTypeTagCategoryBaseSerializer) + EstablishmentTypeBaseSerializer, EstablishmentSubTypeBaseSerializer) + # EstablishmentTypeTagCategoryBaseSerializer) from main.models import Currency from tag.serializers import TagBaseSerializer from utils.decorators import with_base_attributes @@ -146,94 +146,94 @@ class EmployeeBackSerializers(serializers.ModelSerializer): ] -class EstablishmentTagCreateSerializer(serializers.ModelSerializer): - """Serializer for model EstablishmentTag.""" - class Meta: - model = models.EstablishmentTag - fields = [ - 'tag', - 'establishment' - ] - extra_kwargs = { - 'tag': {'write_only': True}, - 'establishment': {'write_only': True}, - } - - def validate(self, attrs): - """Validate method.""" - establishment = attrs.get('establishment') - tag = attrs.get('tag') - - # Check if tag is already added to establishment. - if establishment.tags.filter(tag=tag).exists(): - raise serializers.ValidationError(detail={'detail': _('Tag is already added.')}) - - # Сhecking tag availability for establishment type. - if not establishment.establishment_type.use_subtypes: - qs = establishment.establishment_type.tag_categories.filter(tag_category=tag.category) - else: - # Сhecking tag availability for establishment subtype. - qs = establishment.establishment_type.tag_categories.filter( - establishmentsubtype_set__tag_category=tag.category) - if not qs.exists(): - raise serializers.ValidationError( - detail={'detail': _('Tag is not available for this establishment type|subtype.')}) - return attrs +# class EstablishmentTagCreateSerializer(serializers.ModelSerializer): +# """Serializer for model EstablishmentTag.""" +# class Meta: +# model = models.EstablishmentTag +# fields = [ +# 'tag', +# 'establishment' +# ] +# extra_kwargs = { +# 'tag': {'write_only': True}, +# 'establishment': {'write_only': True}, +# } +# +# def validate(self, attrs): +# """Validate method.""" +# establishment = attrs.get('establishment') +# tag = attrs.get('tag') +# +# # Check if tag is already added to establishment. +# if establishment.tags.filter(tag=tag).exists(): +# raise serializers.ValidationError(detail={'detail': _('Tag is already added.')}) +# +# # Сhecking tag availability for establishment type. +# if not establishment.establishment_type.use_subtypes: +# qs = establishment.establishment_type.tag_categories.filter(tag_category=tag.category) +# else: +# # Сhecking tag availability for establishment subtype. +# qs = establishment.establishment_type.tag_categories.filter( +# establishmentsubtype_set__tag_category=tag.category) +# if not qs.exists(): +# raise serializers.ValidationError( +# detail={'detail': _('Tag is not available for this establishment type|subtype.')}) +# return attrs -class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): - """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" - id = serializers.IntegerField(source='tag_category.id', read_only=True) - label_translated = TranslatedField(source='tag_category.label_translated') - tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) - - class Meta: - """Meta class.""" - model = models.EstablishmentSubTypeTagCategory - fields = [ - 'id', - 'label_translated', - 'tags', - 'establishment_subtype', - 'tag_category', - ] - extra_kwargs = { - 'establishment_subtype': {'write_only': True}, - 'tag_category': {'write_only': True}, - } - - def validate(self, attrs): - """Override validate method.""" - if models.EstablishmentTypeTagCategory.objects.filter( - establishment_type=attrs.get('establishment_type'), - tag_category=attrs.get('tag_category')).exists(): - raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) - return attrs - - -class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer): - """Extended serializer for EstablishmentSubType model with tags.""" - tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True) - - class Meta(EstablishmentSubTypeBaseSerializer.Meta): - """Meta class""" - fields = [ - 'id', - 'name_translated', - 'tag_categories' - ] - - -class EstablishmentTagsByType(EstablishmentTypeBaseSerializer): - """Tags by establishment type""" - tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True) - subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set') - - class Meta(EstablishmentTypeBaseSerializer.Meta): - """Meta class.""" - fields = [ - 'id', - 'name_translated', - 'tag_categories', - 'subtypes', - ] +# class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): +# """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" +# id = serializers.IntegerField(source='tag_category.id', read_only=True) +# label_translated = TranslatedField(source='tag_category.label_translated') +# tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) +# +# class Meta: +# """Meta class.""" +# model = models.EstablishmentSubTypeTagCategory +# fields = [ +# 'id', +# 'label_translated', +# 'tags', +# 'establishment_subtype', +# 'tag_category', +# ] +# extra_kwargs = { +# 'establishment_subtype': {'write_only': True}, +# 'tag_category': {'write_only': True}, +# } +# +# def validate(self, attrs): +# """Override validate method.""" +# if models.EstablishmentTypeTagCategory.objects.filter( +# establishment_type=attrs.get('establishment_type'), +# tag_category=attrs.get('tag_category')).exists(): +# raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) +# return attrs +# +# +# class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer): +# """Extended serializer for EstablishmentSubType model with tags.""" +# tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True) +# +# class Meta(EstablishmentSubTypeBaseSerializer.Meta): +# """Meta class""" +# fields = [ +# 'id', +# 'name_translated', +# 'tag_categories' +# ] +# +# +# class EstablishmentTagsByType(EstablishmentTypeBaseSerializer): +# """Tags by establishment type""" +# tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True) +# subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set') +# +# class Meta(EstablishmentTypeBaseSerializer.Meta): +# """Meta class.""" +# fields = [ +# 'id', +# 'name_translated', +# 'tag_categories', +# 'subtypes', +# ] diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 1789da31..7c659c9b 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -139,34 +139,34 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer): } -class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): - """Serializer for intermediate model EstablishmentTypeTagCategories.""" - id = serializers.IntegerField(source='tag_category.id', read_only=True) - label_translated = TranslatedField(source='tag_category.label_translated') - tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) - - class Meta: - """Meta class.""" - model = models.EstablishmentTypeTagCategory - fields = [ - 'id', - 'label_translated', - 'tags', - 'establishment_type', - 'tag_category', - ] - extra_kwargs = { - 'establishment_type': {'write_only': True}, - 'tag_category': {'write_only': True}, - } - - def validate(self, attrs): - """Override validate method.""" - if models.EstablishmentTypeTagCategory.objects.filter( - establishment_type=attrs.get('establishment_type'), - tag_category=attrs.get('tag_category')).exists(): - raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) - return attrs +# class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): +# """Serializer for intermediate model EstablishmentTypeTagCategories.""" +# id = serializers.IntegerField(source='tag_category.id', read_only=True) +# label_translated = TranslatedField(source='tag_category.label_translated') +# tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) +# +# class Meta: +# """Meta class.""" +# model = models.EstablishmentTypeTagCategory +# fields = [ +# 'id', +# 'label_translated', +# 'tags', +# 'establishment_type', +# 'tag_category', +# ] +# extra_kwargs = { +# 'establishment_type': {'write_only': True}, +# 'tag_category': {'write_only': True}, +# } +# +# def validate(self, attrs): +# """Override validate method.""" +# if models.EstablishmentTypeTagCategory.objects.filter( +# establishment_type=attrs.get('establishment_type'), +# tag_category=attrs.get('tag_category')).exists(): +# raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) +# return attrs class EstablishmentEmployeeSerializer(serializers.ModelSerializer): @@ -184,19 +184,19 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): model = models.Employee fields = ('id', 'name', 'position_translated', 'awards', 'priority') - -class EstablishmentTagSerializer(serializers.ModelSerializer): - """Serializer for intermediate model EstablishmentTag.""" - id = serializers.IntegerField(source='tag.id') - label_translated = serializers.CharField(source='tag.label_translated') - - class Meta: - """Meta class.""" - model = models.EstablishmentTag - fields = [ - 'id', - 'label_translated' - ] +# +# class EstablishmentTagSerializer(serializers.ModelSerializer): +# """Serializer for intermediate model EstablishmentTag.""" +# id = serializers.IntegerField(source='tag.id') +# label_translated = serializers.CharField(source='tag.label_translated') +# +# class Meta: +# """Meta class.""" +# model = models.EstablishmentTag +# fields = [ +# 'id', +# 'label_translated' +# ] class EstablishmentBaseSerializer(ProjectModelSerializer): @@ -206,7 +206,7 @@ class EstablishmentBaseSerializer(ProjectModelSerializer): slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) address = AddressBaseSerializer() in_favorites = serializers.BooleanField(allow_null=True) - tags = EstablishmentTagSerializer(many=True) + tags = TagBaseSerializer(read_only=True, many=True) class Meta: """Meta class.""" diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 3db81dce..cdd4d183 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -14,7 +14,7 @@ urlpatterns = [ name='schedule-rud'), path('/schedule/', views.EstablishmentScheduleCreateView.as_view(), name='schedule-create'), - path('attach-tag/', views.EstablishmentTagCreateView.as_view(), name='attach-tag'), + # path('attach-tag/', views.EstablishmentTagCreateView.as_view(), name='attach-tag'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), @@ -28,12 +28,12 @@ urlpatterns = [ path('employees/', views.EmployeeListCreateView.as_view(), name='employees'), path('employees//', views.EmployeeRUDView.as_view(), name='employees-rud'), path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'), - path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), + # path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), path('types//', views.EstablishmentTypeRUDView.as_view(), name='type-rud'), - path('types/attach-tag-category/', views.EstablishmentTypeAttachTagCategoryView.as_view(), - name='type-attach-tag-category'), + # path('types/attach-tag-category/', views.EstablishmentTypeAttachTagCategoryView.as_view(), + # name='type-attach-tag-category'), path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), - path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), - name='subtype-attach-tag-category'), + # path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), + # name='subtype-attach-tag-category'), ] diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 18b768c0..65b796ae 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -7,7 +7,7 @@ app_name = 'establishment' urlpatterns = [ path('', views.EstablishmentListView.as_view(), name='list'), - path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), + # path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), name='recent-reviews'), path('slug//', views.EstablishmentRetrieveView.as_view(), name='detail'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 543dbd3e..f79707d9 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -55,24 +55,24 @@ class EstablishmentScheduleCreateView(generics.CreateAPIView): serializer_class = ScheduleCreateSerializer -class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): - """Attach tag category to establishment type.""" - serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer - - def get_queryset(self): - """Override get_queryset method.""" - return models.EstablishmentTypeTagCategory.objects.with_base_related() - - def post(self, request, *args, **kwargs): - """Overridden post-method.""" - super(EstablishmentTypeAttachTagCategoryView, self).post(request) - return Response(status=status.HTTP_200_OK) +# class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): +# """Attach tag category to establishment type.""" +# serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer +# +# def get_queryset(self): +# """Override get_queryset method.""" +# return models.EstablishmentTypeTagCategory.objects.with_base_related() +# +# def post(self, request, *args, **kwargs): +# """Overridden post-method.""" +# super(EstablishmentTypeAttachTagCategoryView, self).post(request) +# return Response(status=status.HTTP_200_OK) -class EstablishmentTagCreateView(EstablishmentMixinViews, generics.CreateAPIView): - """Attach tag to establishment.""" - serializer_class = serializers.EstablishmentTagCreateSerializer - +# class EstablishmentTagCreateView(EstablishmentMixinViews, generics.CreateAPIView): +# """Attach tag to establishment.""" +# serializer_class = serializers.EstablishmentTagCreateSerializer +# class MenuListCreateView(generics.ListCreateAPIView): """Menu list create view.""" @@ -164,13 +164,13 @@ class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = models.EstablishmentType.objects.all() -class EstablishmentTypeTagListView(generics.ListAPIView): - """List of tags with categories by establishment type.""" - serializer_class = serializers.EstablishmentTagsByType - queryset = models.EstablishmentType.objects.with_base_related() - filter_class = EstablishmentTypeTagFilter - permission_classes = (permissions.AllowAny, ) - pagination_class = None +# class EstablishmentTypeTagListView(generics.ListAPIView): +# """List of tags with categories by establishment type.""" +# serializer_class = serializers.EstablishmentTagsByType +# queryset = models.EstablishmentType.objects.with_base_related() +# filter_class = EstablishmentTypeTagFilter +# permission_classes = (permissions.AllowAny, ) +# pagination_class = None class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView): @@ -186,15 +186,15 @@ class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = models.EstablishmentSubType.objects.all() -class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): - """Attach tag category to establishment subtype.""" - serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer - - def get_queryset(self): - """Override get_queryset method.""" - return models.EstablishmentSubTypeTagCategory.objects.with_base_related() - - def post(self, request, *args, **kwargs): - """Overridden post-method.""" - super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) - return Response(status=status.HTTP_200_OK) +# class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): +# """Attach tag category to establishment subtype.""" +# serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer +# +# def get_queryset(self): +# """Override get_queryset method.""" +# return models.EstablishmentSubTypeTagCategory.objects.with_base_related() +# +# def post(self, request, *args, **kwargs): +# """Overridden post-method.""" +# super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) +# return Response(status=status.HTTP_200_OK) diff --git a/apps/search_indexes/documents/news.py b/apps/search_indexes/documents/news.py index 6e0974d8..62049c05 100644 --- a/apps/search_indexes/documents/news.py +++ b/apps/search_indexes/documents/news.py @@ -24,15 +24,15 @@ class NewsDocument(Document): country = fields.ObjectField(properties={'id': fields.IntegerField(), 'code': fields.KeywordField()}) web_url = fields.KeywordField(attr='web_url') - tags = fields.ObjectField( - properties={ - 'id': fields.IntegerField(attr='metadata.id'), - 'label': fields.ObjectField(attr='metadata.label_indexing', - properties=OBJECT_FIELD_PROPERTIES), - 'category': fields.ObjectField(attr='metadata.category', - properties={'id': fields.IntegerField()}) - }, - multi=True) + # tags = fields.ObjectField( + # properties={ + # 'id': fields.IntegerField(attr='metadata.id'), + # 'label': fields.ObjectField(attr='metadata.label_indexing', + # properties=OBJECT_FIELD_PROPERTIES), + # 'category': fields.ObjectField(attr='metadata.category', + # properties={'id': fields.IntegerField()}) + # }, + # multi=True) class Django: diff --git a/apps/tag/filters.py b/apps/tag/filters.py new file mode 100644 index 00000000..95f56b53 --- /dev/null +++ b/apps/tag/filters.py @@ -0,0 +1,48 @@ +"""Tag app filters.""" +from django_filters import rest_framework as filters +from tag import models + + +class TagCategoryFilterSet(filters.FilterSet): + """TagCategory filterset.""" + + # Object type choices + NEWS = 'news' + ESTABLISHMENT = 'establishment' + + TYPE_CHOICES = ( + (NEWS, 'News'), + (ESTABLISHMENT, 'Establishment'), + ) + + type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES, + method='filter_by_type') + + # Establishment type choices + RESTAURANT = 'restaurant' + + ESTABLISHMENT_TYPE_CHOICES = ( + (RESTAURANT, 'restaurant'), + ) + + establishment_type = filters.MultipleChoiceFilter( + choices=ESTABLISHMENT_TYPE_CHOICES, + method='filter_by_establishment_type') + + class Meta: + """Meta class.""" + + model = models.TagCategory + fields = ('type', + 'establishment_type', ) + + def filter_by_type(self, queryset, name, value): + if self.NEWS in value: + queryset = queryset.for_news() + if self.ESTABLISHMENT in value: + queryset = queryset.for_establishments() + return queryset + + # todo: filter by establishment type + def filter_by_establishment_type(self, queryset, name, value): + return queryset.for_establishments() diff --git a/apps/tag/models.py b/apps/tag/models.py index b552bbcb..381e552d 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -32,8 +32,16 @@ class Tag(TranslatedFieldsMixin, models.Model): class TagCategoryQuerySet(models.QuerySet): """Extended queryset for TagCategory model.""" - def by_news_type(self, news_type): - return self.filter(news_types=news_type) + def with_base_related(self): + return self.prefetch_related('tags') + + def for_news(self): + return self.filter(news_types__isnull=True) + + def for_establishments(self): + return self.filter(models.Q(est_subtype_tag_categories__isnull=True) | + models.Q(est_type_tag_categories__isnull=True)).\ + distinct() def with_related(self): return self.select_related('country').prefetch_related('tags') diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index ecb1b68d..895fe2a1 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -13,23 +13,29 @@ class TagBaseSerializer(serializers.ModelSerializer): """Meta class.""" model = models.Tag - fields = [ + fields = ( 'id', - 'label', 'label_translated', + ) + + +class TagBackOfficeSerializer(TagBaseSerializer): + """Serializer for Tag model for Back office users.""" + + class Meta(TagBaseSerializer.Meta): + """Meta class.""" + + fields = TagBaseSerializer.Meta.fields + ( + 'label', 'category' - ] - extra_kwargs = { - 'label': {'write_only': True}, - 'category': {'write_only': True} - } + ) class TagCategoryBaseSerializer(serializers.ModelSerializer): """Serializer for model TagCategory.""" label_translated = TranslatedField() - country_translated = TranslatedField(source='country.name_translated') + tags = TagBaseSerializer(many=True, read_only=True) class Meta: """Meta class.""" @@ -37,23 +43,29 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer): model = models.TagCategory fields = ( 'id', - 'label', 'label_translated', - 'country', - 'country_translated', - 'public', + 'tags' ) - extra_kwargs = { - 'label': {'write_only': True}, - 'country': {'write_only': True}, - } class TagCategoryDetailSerializer(TagCategoryBaseSerializer): - tags = TagBaseSerializer(many=True) class Meta(TagCategoryBaseSerializer.Meta): """Meta class.""" fields = TagCategoryBaseSerializer.Meta.fields + ('tags', ) + + +class TagCategoryBackOfficeDetailSerializer(TagCategoryDetailSerializer): + + country_translated = TranslatedField(source='country.name_translated') + + class Meta(TagCategoryDetailSerializer.Meta): + """Meta class.""" + + fields = TagCategoryDetailSerializer.Meta.fields + ( + 'news_types', + 'country', + 'country_translated', + ) diff --git a/apps/tag/urls/__init__.py b/apps/tag/urls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/tag/urls.py b/apps/tag/urls/back.py similarity index 53% rename from apps/tag/urls.py rename to apps/tag/urls/back.py index 0d0b86d2..9f03bb45 100644 --- a/apps/tag/urls.py +++ b/apps/tag/urls/back.py @@ -1,10 +1,16 @@ """Urlconf for app tag.""" from django.urls import path -from . import views +from rest_framework.routers import SimpleRouter +from tag import views app_name = 'tag' +router = SimpleRouter() +router.register(r'', views.TagViewSet) + + urlpatterns = [ - path('', views.TagListCreateView.as_view(), name='list-create'), path('category/', views.TagCategoryListCreateView.as_view(), name='category-list-create'), ] + +urlpatterns += router.urls diff --git a/apps/tag/urls/web.py b/apps/tag/urls/web.py new file mode 100644 index 00000000..c99253eb --- /dev/null +++ b/apps/tag/urls/web.py @@ -0,0 +1,16 @@ +"""Tag app urlpatterns web users.""" +from rest_framework.routers import SimpleRouter +from tag import views + + +app_name = 'tag' + +router = SimpleRouter() +router.register(r'categories', views.TagCategoryViewSet) + +urlpatterns = [ + +] + +urlpatterns += router.urls + diff --git a/apps/tag/views.py b/apps/tag/views.py index 5bf4d045..2bc9d8d2 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -1,19 +1,33 @@ """Tag views.""" -from rest_framework import generics -from tag import serializers, models +from rest_framework import generics, viewsets, mixins +from tag import filters, models, serializers +from rest_framework import permissions -class TagListCreateView(generics.ListCreateAPIView): +class TagViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, + mixins.UpdateModelMixin, mixins.DestroyModelMixin, + viewsets.GenericViewSet): """List/create tag view.""" - queryset = models.Tag.objects.all() - serializer_class = serializers.TagBaseSerializer pagination_class = None + queryset = models.Tag.objects.all() + serializer_class = serializers.TagBackOfficeSerializer class TagCategoryListCreateView(generics.ListCreateAPIView): """List/create tag category view.""" - queryset = models.TagCategory.objects.all() - serializer_class = serializers.TagCategoryBaseSerializer pagination_class = None + permission_classes = (permissions.AllowAny, ) + queryset = models.TagCategory.objects.all() + serializer_class = serializers.TagCategoryBackOfficeDetailSerializer + + +class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): + """ViewSet for TagCategory model.""" + + filterset_class = filters.TagCategoryFilterSet + pagination_class = None + permission_classes = (permissions.AllowAny, ) + queryset = models.TagCategory.objects.with_base_related() + serializer_class = serializers.TagCategoryBaseSerializer diff --git a/project/settings/base.py b/project/settings/base.py index 4618887d..1de0c109 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -222,8 +222,8 @@ REST_FRAMEWORK = { 'COERCE_DECIMAL_TO_STRING': False, 'DEFAULT_AUTHENTICATION_CLASSES': ( # JWT - 'utils.authentication.GMJWTAuthentication', 'rest_framework.authentication.SessionAuthentication', + # 'utils.authentication.GMJWTAuthentication', ), 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', 'DEFAULT_VERSION': (AVAILABLE_VERSIONS['current'],), diff --git a/project/urls/back.py b/project/urls/back.py index eb049b9c..389c6f51 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -7,7 +7,7 @@ urlpatterns = [ path('establishments/', include('establishment.urls.back')), path('location/', include('location.urls.back')), path('news/', include('news.urls.back')), - path('tags/', include(('tag.urls', 'tag'), namespace='tag')), + path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')), path('account/', include('account.urls.back')), path('comment/', include('comment.urls.back')), ] diff --git a/project/urls/web.py b/project/urls/web.py index 89debab2..5bd67207 100644 --- a/project/urls/web.py +++ b/project/urls/web.py @@ -30,6 +30,7 @@ urlpatterns = [ path('location/', include('location.urls.web')), path('main/', include('main.urls')), path('recipes/', include('recipe.urls.web')), + path('tags/', include('tag.urls.web')), path('translation/', include('translation.urls')), path('comments/', include('comment.urls.web')), path('favorites/', include('favorites.urls')), From c94ad3f017e24680ef9b483a0b49ea5139ff99f5 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 17:48:01 +0300 Subject: [PATCH 15/25] comment some code --- apps/search_indexes/documents/establishment.py | 14 +++++++------- apps/tag/models.py | 7 ++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index e2147fbc..5d45c45b 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -39,13 +39,13 @@ class EstablishmentDocument(Document): }), }, multi=True) - tags = fields.ObjectField( - properties={ - 'tag': fields.ObjectField(properties={ - 'id': fields.IntegerField(), - }), - }, - multi=True) + # tags = fields.ObjectField( + # properties={ + # 'tag': fields.ObjectField(properties={ + # 'id': fields.IntegerField(), + # }), + # }, + # multi=True) address = fields.ObjectField( properties={ 'id': fields.IntegerField(), diff --git a/apps/tag/models.py b/apps/tag/models.py index 381e552d..32cbfa05 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -39,9 +39,10 @@ class TagCategoryQuerySet(models.QuerySet): return self.filter(news_types__isnull=True) def for_establishments(self): - return self.filter(models.Q(est_subtype_tag_categories__isnull=True) | - models.Q(est_type_tag_categories__isnull=True)).\ - distinct() + return self + # return self.filter(models.Q(est_subtype_tag_categories__isnull=True) | + # models.Q(est_type_tag_categories__isnull=True)).\ + # distinct() def with_related(self): return self.select_related('country').prefetch_related('tags') From 42ae1cbb8773636dbbd956e2742c18360496c6cd Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 18:13:37 +0300 Subject: [PATCH 16/25] fix tagcategory queryset --- apps/tag/models.py | 13 +++++++++---- apps/tag/serializers.py | 2 +- apps/tag/views.py | 13 ++----------- project/urls/back.py | 2 +- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/tag/models.py b/apps/tag/models.py index 32cbfa05..3deed7d9 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -33,16 +33,21 @@ class TagCategoryQuerySet(models.QuerySet): """Extended queryset for TagCategory model.""" def with_base_related(self): + """Select related objects.""" return self.prefetch_related('tags') def for_news(self): + """Select tag categories for news.""" return self.filter(news_types__isnull=True) def for_establishments(self): - return self - # return self.filter(models.Q(est_subtype_tag_categories__isnull=True) | - # models.Q(est_type_tag_categories__isnull=True)).\ - # distinct() + """Select tag categories for establishments.""" + return self.filter(models.Q(establishment_types__isnull=False) | + models.Q(establishment_subtypes__isnull=False)) + + def with_tags(self, switcher=True): + """Filter by existing tags.""" + return self.filter(tags__isnull=not switcher) def with_related(self): return self.select_related('country').prefetch_related('tags') diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index 895fe2a1..946206f4 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -49,7 +49,7 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer): class TagCategoryDetailSerializer(TagCategoryBaseSerializer): - + """Detailed serializer for TagCategory model.""" class Meta(TagCategoryBaseSerializer.Meta): """Meta class.""" diff --git a/apps/tag/views.py b/apps/tag/views.py index 2bc9d8d2..622ec849 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -1,5 +1,5 @@ """Tag views.""" -from rest_framework import generics, viewsets, mixins +from rest_framework import viewsets, mixins from tag import filters, models, serializers from rest_framework import permissions @@ -14,20 +14,11 @@ class TagViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, serializer_class = serializers.TagBackOfficeSerializer -class TagCategoryListCreateView(generics.ListCreateAPIView): - """List/create tag category view.""" - - pagination_class = None - permission_classes = (permissions.AllowAny, ) - queryset = models.TagCategory.objects.all() - serializer_class = serializers.TagCategoryBackOfficeDetailSerializer - - class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ViewSet for TagCategory model.""" filterset_class = filters.TagCategoryFilterSet pagination_class = None permission_classes = (permissions.AllowAny, ) - queryset = models.TagCategory.objects.with_base_related() + queryset = models.TagCategory.objects.with_tags().with_base_related() serializer_class = serializers.TagCategoryBaseSerializer diff --git a/project/urls/back.py b/project/urls/back.py index 389c6f51..5d221932 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -7,7 +7,7 @@ urlpatterns = [ path('establishments/', include('establishment.urls.back')), path('location/', include('location.urls.back')), path('news/', include('news.urls.back')), - path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')), + # path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')), path('account/', include('account.urls.back')), path('comment/', include('comment.urls.back')), ] From 9d4c483f514554dd1adc504e2b4d1f47350d46b3 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 18:25:09 +0300 Subject: [PATCH 17/25] clean models (tags) --- apps/establishment/admin.py | 15 ---- apps/establishment/models.py | 109 +---------------------- apps/establishment/serializers/back.py | 99 +------------------- apps/establishment/serializers/common.py | 44 --------- apps/establishment/urls/back.py | 6 -- apps/establishment/urls/common.py | 1 - apps/establishment/views/back.py | 46 +--------- apps/news/admin.py | 2 +- apps/news/urls/web.py | 2 - apps/news/views.py | 13 --- apps/tag/models.py | 3 - apps/tag/serializers.py | 15 +--- 12 files changed, 8 insertions(+), 347 deletions(-) diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index 8a5e57de..50c21b90 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -79,18 +79,3 @@ class MenuAdmin(admin.ModelAdmin): return obj.category_translated category_translated.short_description = _('category') - -# -# @admin.register(models.EstablishmentTypeTagCategory) -# class EstablishmentTypeTagCategoryAdmin(admin.ModelAdmin): -# """EstablishmentTypeTagCategory admin.""" -# -# -# @admin.register(models.EstablishmentSubTypeTagCategory) -# class EstablishmentSubTypeTagCategoryAdmin(admin.ModelAdmin): -# """EstablishmentTypeTagCategory admin.""" -# -# -# @admin.register(models.EstablishmentTag) -# class EstablishmentTagAdmin(admin.ModelAdmin): -# """EstablishmentTag admin.""" diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 14d7e02b..c93bbf89 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -16,29 +16,11 @@ from phonenumber_field.modelfields import PhoneNumberField from collection.models import Collection from location.models import Address from main.models import Award -from tag.models import Tag, TagCategory from review.models import Review from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, TranslatedFieldsMixin, BaseAttributes) -class EstablishmentTypeQuerySet(models.QuerySet): - """QuerySet for model EstablishmentType.""" - - def with_base_related(self): - """Return QuerySet with base related.""" - return self - # return self.prefetch_related( - # models.Prefetch('tag_categories', - # EstablishmentTypeTagCategory.objects.select_related('tag_category')), - # models.Prefetch('establishmentsubtype_set', - # EstablishmentSubType.objects.prefetch_related( - # models.Prefetch( - # 'tag_categories', - # EstablishmentSubTypeTagCategory.objects.select_related('tag_category')))) - # ) - - # todo: establishment type&subtypes check class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): """Establishment type model.""" @@ -52,8 +34,6 @@ class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): related_name='establishment_types', verbose_name=_('Tag')) - objects = EstablishmentTypeQuerySet.as_manager() - class Meta: """Meta class.""" @@ -101,15 +81,8 @@ class EstablishmentQuerySet(models.QuerySet): def with_base_related(self): """Return qs with related objects.""" - return self - # return self.select_related('address', 'establishment_type').prefetch_related( - # models.Prefetch('tags', - # EstablishmentTag.objects.select_related('tag')), - # models.Prefetch('establishment_type__tag_categories', - # EstablishmentTypeTagCategory.objects.select_related('tag_category')), - # models.Prefetch('establishment_type__establishmentsubtype_set', - # EstablishmentSubType.objects.prefetch_related('tag_categories')), - # ) + return self.select_related('address', 'establishment_type').\ + prefetch_related('tags') def with_extended_related(self): return self.select_related('establishment_type').\ @@ -587,81 +560,3 @@ class SocialNetwork(models.Model): def __str__(self): return self.title -# -# class EstablishmentTagQuerySet(models.QuerySet): -# """Establishment tag QuerySet.""" -# -# def by_country_code(self, code): -# """Return establishment tags by establishment country code.""" -# return self.filter(establishment__address__city__country__code=code) - -# -# class EstablishmentTag(models.Model): -# """Establishment tag model.""" -# tag = models.ForeignKey('tag.Tag', -# on_delete=models.CASCADE, -# related_name='tags', -# verbose_name=_('tag')) -# establishment = models.ForeignKey('establishment.Establishment', -# on_delete=models.CASCADE, -# related_name='tags', -# verbose_name=_('establishment')) -# objects = EstablishmentTagQuerySet.as_manager() -# -# class Meta: -# verbose_name = _('establishment tag') -# verbose_name_plural = _('establishment tags') -# -# -# class EstablishmentTypeTagCategoryQuerySet(models.QuerySet): -# """EstablishmentTypeTagCategory QuerySet.""" -# -# def by_country_code(self, code): -# """Return establishment tags by country code""" -# return self.filter(tag_category__country__code=code) -# -# def with_base_related(self): -# """Return with related relations.""" -# return self.select_related('establishment_type', 'tag_category') -# -# -# class EstablishmentTypeTagCategory(models.Model): -# """Tag categories based on establishment type.""" -# establishment_type = models.ForeignKey(EstablishmentType, -# on_delete=models.CASCADE, -# related_name='tag_categories', -# verbose_name=_('establishment type')) -# tag_category = models.ForeignKey('tag.TagCategory', -# on_delete=models.CASCADE, -# related_name='est_type_tag_categories', -# verbose_name=_('tag category')) -# objects = EstablishmentTypeTagCategoryQuerySet.as_manager() -# -# class Meta: -# verbose_name = _('establishment type tag categories') -# verbose_name_plural = _('establishment type tag categories') -# -# -# class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet): -# """QuerySet for tag categories based on establishment subtype.""" -# -# def with_base_related(self): -# """Return queryset with base related.""" -# return self.select_related('establishment_subtype', 'tag_category') -# -# -# class EstablishmentSubTypeTagCategory(models.Model): -# """Tag categories based on establishment subtype.""" -# establishment_subtype = models.ForeignKey(EstablishmentSubType, -# on_delete=models.CASCADE, -# related_name='tag_categories', -# verbose_name=_('establishment subtype')) -# tag_category = models.ForeignKey('tag.TagCategory', -# on_delete=models.CASCADE, -# related_name='est_subtype_tag_categories', -# verbose_name=_('tag category')) -# objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager() -# -# class Meta: -# verbose_name = _('establishment subtype tag categories') -# verbose_name_plural = _('establishment subtype tag categories') diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index dca25763..59725710 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,16 +1,12 @@ -from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from establishment import models from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, ContactPhonesSerializer, SocialNetworkRelatedSerializers, - EstablishmentTypeBaseSerializer, EstablishmentSubTypeBaseSerializer) - # EstablishmentTypeTagCategoryBaseSerializer) + EstablishmentTypeBaseSerializer) from main.models import Currency -from tag.serializers import TagBaseSerializer from utils.decorators import with_base_attributes -from utils.serializers import TranslatedField class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): @@ -144,96 +140,3 @@ class EmployeeBackSerializers(serializers.ModelSerializer): 'user', 'name' ] - - -# class EstablishmentTagCreateSerializer(serializers.ModelSerializer): -# """Serializer for model EstablishmentTag.""" -# class Meta: -# model = models.EstablishmentTag -# fields = [ -# 'tag', -# 'establishment' -# ] -# extra_kwargs = { -# 'tag': {'write_only': True}, -# 'establishment': {'write_only': True}, -# } -# -# def validate(self, attrs): -# """Validate method.""" -# establishment = attrs.get('establishment') -# tag = attrs.get('tag') -# -# # Check if tag is already added to establishment. -# if establishment.tags.filter(tag=tag).exists(): -# raise serializers.ValidationError(detail={'detail': _('Tag is already added.')}) -# -# # Сhecking tag availability for establishment type. -# if not establishment.establishment_type.use_subtypes: -# qs = establishment.establishment_type.tag_categories.filter(tag_category=tag.category) -# else: -# # Сhecking tag availability for establishment subtype. -# qs = establishment.establishment_type.tag_categories.filter( -# establishmentsubtype_set__tag_category=tag.category) -# if not qs.exists(): -# raise serializers.ValidationError( -# detail={'detail': _('Tag is not available for this establishment type|subtype.')}) -# return attrs - - -# class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer): -# """Serializer for intermediate model EstablishmentSubTypeTagCategories.""" -# id = serializers.IntegerField(source='tag_category.id', read_only=True) -# label_translated = TranslatedField(source='tag_category.label_translated') -# tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) -# -# class Meta: -# """Meta class.""" -# model = models.EstablishmentSubTypeTagCategory -# fields = [ -# 'id', -# 'label_translated', -# 'tags', -# 'establishment_subtype', -# 'tag_category', -# ] -# extra_kwargs = { -# 'establishment_subtype': {'write_only': True}, -# 'tag_category': {'write_only': True}, -# } -# -# def validate(self, attrs): -# """Override validate method.""" -# if models.EstablishmentTypeTagCategory.objects.filter( -# establishment_type=attrs.get('establishment_type'), -# tag_category=attrs.get('tag_category')).exists(): -# raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) -# return attrs -# -# -# class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer): -# """Extended serializer for EstablishmentSubType model with tags.""" -# tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True) -# -# class Meta(EstablishmentSubTypeBaseSerializer.Meta): -# """Meta class""" -# fields = [ -# 'id', -# 'name_translated', -# 'tag_categories' -# ] -# -# -# class EstablishmentTagsByType(EstablishmentTypeBaseSerializer): -# """Tags by establishment type""" -# tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True) -# subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set') -# -# class Meta(EstablishmentTypeBaseSerializer.Meta): -# """Meta class.""" -# fields = [ -# 'id', -# 'name_translated', -# 'tag_categories', -# 'subtypes', -# ] diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 7c659c9b..389d0d1c 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -139,36 +139,6 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer): } -# class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer): -# """Serializer for intermediate model EstablishmentTypeTagCategories.""" -# id = serializers.IntegerField(source='tag_category.id', read_only=True) -# label_translated = TranslatedField(source='tag_category.label_translated') -# tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True) -# -# class Meta: -# """Meta class.""" -# model = models.EstablishmentTypeTagCategory -# fields = [ -# 'id', -# 'label_translated', -# 'tags', -# 'establishment_type', -# 'tag_category', -# ] -# extra_kwargs = { -# 'establishment_type': {'write_only': True}, -# 'tag_category': {'write_only': True}, -# } -# -# def validate(self, attrs): -# """Override validate method.""" -# if models.EstablishmentTypeTagCategory.objects.filter( -# establishment_type=attrs.get('establishment_type'), -# tag_category=attrs.get('tag_category')).exists(): -# raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')}) -# return attrs - - class EstablishmentEmployeeSerializer(serializers.ModelSerializer): """Serializer for actual employees.""" @@ -184,20 +154,6 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): model = models.Employee fields = ('id', 'name', 'position_translated', 'awards', 'priority') -# -# class EstablishmentTagSerializer(serializers.ModelSerializer): -# """Serializer for intermediate model EstablishmentTag.""" -# id = serializers.IntegerField(source='tag.id') -# label_translated = serializers.CharField(source='tag.label_translated') -# -# class Meta: -# """Meta class.""" -# model = models.EstablishmentTag -# fields = [ -# 'id', -# 'label_translated' -# ] - class EstablishmentBaseSerializer(ProjectModelSerializer): """Base serializer for Establishment model.""" diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index cdd4d183..6a12e792 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -14,7 +14,6 @@ urlpatterns = [ name='schedule-rud'), path('/schedule/', views.EstablishmentScheduleCreateView.as_view(), name='schedule-create'), - # path('attach-tag/', views.EstablishmentTagCreateView.as_view(), name='attach-tag'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), @@ -28,12 +27,7 @@ urlpatterns = [ path('employees/', views.EmployeeListCreateView.as_view(), name='employees'), path('employees//', views.EmployeeRUDView.as_view(), name='employees-rud'), path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'), - # path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), path('types//', views.EstablishmentTypeRUDView.as_view(), name='type-rud'), - # path('types/attach-tag-category/', views.EstablishmentTypeAttachTagCategoryView.as_view(), - # name='type-attach-tag-category'), path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), - # path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(), - # name='subtype-attach-tag-category'), ] diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 65b796ae..5d7df146 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -7,7 +7,6 @@ app_name = 'establishment' urlpatterns = [ path('', views.EstablishmentListView.as_view(), name='list'), - # path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), name='recent-reviews'), path('slug//', views.EstablishmentRetrieveView.as_view(), name='detail'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index f79707d9..d87baf6d 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,11 +1,9 @@ """Establishment app views.""" from django.shortcuts import get_object_or_404 -from rest_framework import generics, status, permissions +from rest_framework import generics from establishment import models, serializers -from rest_framework.response import Response from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer -from establishment.filters import EstablishmentTypeTagFilter class EstablishmentMixinViews: @@ -55,25 +53,6 @@ class EstablishmentScheduleCreateView(generics.CreateAPIView): serializer_class = ScheduleCreateSerializer -# class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView): -# """Attach tag category to establishment type.""" -# serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer -# -# def get_queryset(self): -# """Override get_queryset method.""" -# return models.EstablishmentTypeTagCategory.objects.with_base_related() -# -# def post(self, request, *args, **kwargs): -# """Overridden post-method.""" -# super(EstablishmentTypeAttachTagCategoryView, self).post(request) -# return Response(status=status.HTTP_200_OK) - - -# class EstablishmentTagCreateView(EstablishmentMixinViews, generics.CreateAPIView): -# """Attach tag to establishment.""" -# serializer_class = serializers.EstablishmentTagCreateSerializer -# - class MenuListCreateView(generics.ListCreateAPIView): """Menu list create view.""" serializer_class = serializers.MenuSerializers @@ -164,15 +143,6 @@ class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = models.EstablishmentType.objects.all() -# class EstablishmentTypeTagListView(generics.ListAPIView): -# """List of tags with categories by establishment type.""" -# serializer_class = serializers.EstablishmentTagsByType -# queryset = models.EstablishmentType.objects.with_base_related() -# filter_class = EstablishmentTypeTagFilter -# permission_classes = (permissions.AllowAny, ) -# pagination_class = None - - class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView): """Establishment subtype list/create view.""" serializer_class = serializers.EstablishmentSubTypeBaseSerializer @@ -184,17 +154,3 @@ class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView): """Establishment subtype retrieve/update/destroy view.""" serializer_class = serializers.EstablishmentSubTypeBaseSerializer queryset = models.EstablishmentSubType.objects.all() - - -# class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView): -# """Attach tag category to establishment subtype.""" -# serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer -# -# def get_queryset(self): -# """Override get_queryset method.""" -# return models.EstablishmentSubTypeTagCategory.objects.with_base_related() -# -# def post(self, request, *args, **kwargs): -# """Overridden post-method.""" -# super(EstablishmentSubTypeAttachTagCategoryView, self).post(request) -# return Response(status=status.HTTP_200_OK) diff --git a/apps/news/admin.py b/apps/news/admin.py index 77ea8388..5d7f79f0 100644 --- a/apps/news/admin.py +++ b/apps/news/admin.py @@ -1,8 +1,8 @@ from django.contrib import admin - from news import models from .tasks import send_email_with_news + @admin.register(models.NewsType) class NewsTypeAdmin(admin.ModelAdmin): """News type admin.""" diff --git a/apps/news/urls/web.py b/apps/news/urls/web.py index 0671f5f6..80fcf072 100644 --- a/apps/news/urls/web.py +++ b/apps/news/urls/web.py @@ -7,7 +7,5 @@ app_name = 'news' urlpatterns = [ path('', views.NewsListView.as_view(), name='list'), path('types/', views.NewsTypeListView.as_view(), name='type'), - path('types//tags/', views.NewsTypeTagsView.as_view(), - name='type-tags'), path('slug//', views.NewsDetailView.as_view(), name='rud'), ] diff --git a/apps/news/views.py b/apps/news/views.py index 1a845a7b..b167324e 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -3,7 +3,6 @@ from django.shortcuts import get_object_or_404 from rest_framework import generics, permissions from news import filters, models, serializers from rating.tasks import add_rating -from tag.serializers import TagCategoryDetailSerializer class NewsMixinView: @@ -47,18 +46,6 @@ class NewsTypeListView(generics.ListAPIView): serializer_class = serializers.NewsTypeSerializer -class NewsTypeTagsView(generics.ListAPIView): - """Resource to get a list of tags for a news type.""" - - pagination_class = None - permission_classes = (permissions.AllowAny, ) - serializer_class = TagCategoryDetailSerializer - - def get_queryset(self): - news_type = get_object_or_404(models.NewsType, pk=self.kwargs.get('pk')) - return news_type.tag_categories.with_related() - - class NewsBackOfficeMixinView: """News back office mixin view.""" diff --git a/apps/tag/models.py b/apps/tag/models.py index 3deed7d9..4fa04f8e 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -49,9 +49,6 @@ class TagCategoryQuerySet(models.QuerySet): """Filter by existing tags.""" return self.filter(tags__isnull=not switcher) - def with_related(self): - return self.select_related('country').prefetch_related('tags') - class TagCategory(TranslatedFieldsMixin, models.Model): """Tag base category model.""" diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index 946206f4..e4ecf25d 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -48,23 +48,14 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer): ) -class TagCategoryDetailSerializer(TagCategoryBaseSerializer): - """Detailed serializer for TagCategory model.""" - - class Meta(TagCategoryBaseSerializer.Meta): - """Meta class.""" - - fields = TagCategoryBaseSerializer.Meta.fields + ('tags', ) - - -class TagCategoryBackOfficeDetailSerializer(TagCategoryDetailSerializer): +class TagCategoryBackOfficeDetailSerializer(TagCategoryBaseSerializer): country_translated = TranslatedField(source='country.name_translated') - class Meta(TagCategoryDetailSerializer.Meta): + class Meta(TagBaseSerializer.Meta): """Meta class.""" - fields = TagCategoryDetailSerializer.Meta.fields + ( + fields = TagCategoryBaseSerializer.Meta.fields + ( 'news_types', 'country', 'country_translated', From bde81b3700b16f6950b1d490e446ce040aab3110 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 18:32:16 +0300 Subject: [PATCH 18/25] update ES documents --- apps/search_indexes/documents/establishment.py | 16 +++++++++------- apps/search_indexes/documents/news.py | 18 +++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index 5d45c45b..6a00f0f1 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -39,13 +39,15 @@ class EstablishmentDocument(Document): }), }, multi=True) - # tags = fields.ObjectField( - # properties={ - # 'tag': fields.ObjectField(properties={ - # 'id': fields.IntegerField(), - # }), - # }, - # multi=True) + tags = fields.ObjectField( + properties={ + 'id': fields.IntegerField(attr='id'), + 'label': fields.ObjectField(attr='label_indexing', + properties=OBJECT_FIELD_PROPERTIES), + 'category': fields.ObjectField(attr='category', + properties={'id': fields.IntegerField()}) + }, + multi=True) address = fields.ObjectField( properties={ 'id': fields.IntegerField(), diff --git a/apps/search_indexes/documents/news.py b/apps/search_indexes/documents/news.py index 62049c05..25eec31d 100644 --- a/apps/search_indexes/documents/news.py +++ b/apps/search_indexes/documents/news.py @@ -24,15 +24,15 @@ class NewsDocument(Document): country = fields.ObjectField(properties={'id': fields.IntegerField(), 'code': fields.KeywordField()}) web_url = fields.KeywordField(attr='web_url') - # tags = fields.ObjectField( - # properties={ - # 'id': fields.IntegerField(attr='metadata.id'), - # 'label': fields.ObjectField(attr='metadata.label_indexing', - # properties=OBJECT_FIELD_PROPERTIES), - # 'category': fields.ObjectField(attr='metadata.category', - # properties={'id': fields.IntegerField()}) - # }, - # multi=True) + tags = fields.ObjectField( + properties={ + 'id': fields.IntegerField(attr='id'), + 'label': fields.ObjectField(attr='label_indexing', + properties=OBJECT_FIELD_PROPERTIES), + 'category': fields.ObjectField(attr='category', + properties={'id': fields.IntegerField()}) + }, + multi=True) class Django: From 3a54b70093df293e9b893a0de8efda80f79557fa Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 18:43:08 +0300 Subject: [PATCH 19/25] update tag on document index --- apps/search_indexes/documents/establishment.py | 2 -- apps/search_indexes/documents/news.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index 6a00f0f1..ca1da993 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -44,8 +44,6 @@ class EstablishmentDocument(Document): 'id': fields.IntegerField(attr='id'), 'label': fields.ObjectField(attr='label_indexing', properties=OBJECT_FIELD_PROPERTIES), - 'category': fields.ObjectField(attr='category', - properties={'id': fields.IntegerField()}) }, multi=True) address = fields.ObjectField( diff --git a/apps/search_indexes/documents/news.py b/apps/search_indexes/documents/news.py index 25eec31d..99071e53 100644 --- a/apps/search_indexes/documents/news.py +++ b/apps/search_indexes/documents/news.py @@ -29,8 +29,6 @@ class NewsDocument(Document): 'id': fields.IntegerField(attr='id'), 'label': fields.ObjectField(attr='label_indexing', properties=OBJECT_FIELD_PROPERTIES), - 'category': fields.ObjectField(attr='category', - properties={'id': fields.IntegerField()}) }, multi=True) From ccf6e12e3f949658d32342682170e70d578a65a0 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 15 Oct 2019 18:52:32 +0300 Subject: [PATCH 20/25] remove tag category from establishment type --- apps/search_indexes/documents/establishment.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index ca1da993..c30d4c58 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -22,13 +22,6 @@ class EstablishmentDocument(Document): 'id': fields.IntegerField(), 'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES), - 'tag_categories': fields.ObjectField(properties={ - 'tag_category': fields.ObjectField( - properties={ - 'id': fields.IntegerField() - } - ) - }), }) establishment_subtypes = fields.ObjectField( properties={ From 19b3502f582601adbed20e1a1272c2197a4a9fa3 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Thu, 17 Oct 2019 14:34:31 +0300 Subject: [PATCH 21/25] revert auth backends --- project/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/settings/base.py b/project/settings/base.py index 1de0c109..4618887d 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -222,8 +222,8 @@ REST_FRAMEWORK = { 'COERCE_DECIMAL_TO_STRING': False, 'DEFAULT_AUTHENTICATION_CLASSES': ( # JWT + 'utils.authentication.GMJWTAuthentication', 'rest_framework.authentication.SessionAuthentication', - # 'utils.authentication.GMJWTAuthentication', ), 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', 'DEFAULT_VERSION': (AVAILABLE_VERSIONS['current'],), From 9661de481075b94978f8093d4126a727b016e7bf Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Thu, 17 Oct 2019 15:17:29 +0300 Subject: [PATCH 22/25] Establishment types --- .../0038_establishmenttype_index_name.py | 34 +++++++++++++++++++ apps/establishment/models.py | 14 ++++++++ apps/search_indexes/signals.py | 16 +++------ apps/tag/filters.py | 18 ++++------ apps/tag/models.py | 4 +++ apps/tag/views.py | 3 +- 6 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 apps/establishment/migrations/0038_establishmenttype_index_name.py diff --git a/apps/establishment/migrations/0038_establishmenttype_index_name.py b/apps/establishment/migrations/0038_establishmenttype_index_name.py new file mode 100644 index 00000000..657dbe42 --- /dev/null +++ b/apps/establishment/migrations/0038_establishmenttype_index_name.py @@ -0,0 +1,34 @@ +# Generated by Django 2.2.4 on 2019-10-16 11:33 + +from django.db import migrations, models + + +def fill_establishment_type(apps, schemaeditor): + import ipdb; ipdb.set_trace() + EstablishmentType = apps.get_model('establishment', 'EstablishmentType') + for n, et in enumerate(EstablishmentType.objects.all()): + et.index_name = f'Type {n}' + et.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0037_auto_20191015_1404'), + ] + + operations = [ + migrations.AddField( + model_name='establishmenttype', + name='index_name', + field=models.CharField(blank=True, db_index=True, max_length=50, null=True, unique=True, default=None, verbose_name='Index name'), + ), + migrations.RunPython(fill_establishment_type, migrations.RunPython.noop), + migrations.AlterField( + model_name='establishmenttype', + name='index_name', + field=models.CharField(choices=[('restaurant', 'Restaurant'), ('artisan', 'Artisan'), + ('producer', 'Producer')], db_index=True, max_length=50, + unique=True, verbose_name='Index name'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index c93bbf89..7466414c 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -27,8 +27,22 @@ class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): STR_FIELD_NAME = 'name' + # INDEX NAME CHOICES + RESTAURANT = 'restaurant' + ARTISAN = 'artisan' + PRODUCER = 'producer' + + INDEX_NAME_TYPES = ( + (RESTAURANT, _('Restaurant')), + (ARTISAN, _('Artisan')), + (PRODUCER, _('Producer')), + ) + name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), help_text='{"en-GB":"some text"}') + index_name = models.CharField(max_length=50, choices=INDEX_NAME_TYPES, + unique=True, db_index=True, + verbose_name=_('Index name')) use_subtypes = models.BooleanField(_('Use subtypes'), default=True) tag_categories = models.ManyToManyField('tag.TagCategory', related_name='establishment_types', diff --git a/apps/search_indexes/signals.py b/apps/search_indexes/signals.py index f7520b57..0f6a071f 100644 --- a/apps/search_indexes/signals.py +++ b/apps/search_indexes/signals.py @@ -40,12 +40,8 @@ def update_document(sender, **kwargs): for establishment in establishments: registry.update(establishment) - if app_label == 'main': - if model_name == 'metadata': - establishments = Establishment.objects.filter(tags__metadata=instance) - for establishment in establishments: - registry.update(establishment) - if model_name == 'metadatacontent': + if app_label == 'tag': + if model_name == 'tag': establishments = Establishment.objects.filter(tags=instance) for establishment in establishments: registry.update(establishment) @@ -70,12 +66,8 @@ def update_news(sender, **kwargs): for news in qs: registry.update(news) - if app_label == 'main': - if model_name == 'metadata': - qs = News.objects.filter(tags__metadata=instance) - for news in qs: - registry.update(news) - if model_name == 'metadatacontent': + if app_label == 'tag': + if model_name == 'tag': qs = News.objects.filter(tags=instance) for news in qs: registry.update(news) diff --git a/apps/tag/filters.py b/apps/tag/filters.py index 95f56b53..8816f820 100644 --- a/apps/tag/filters.py +++ b/apps/tag/filters.py @@ -1,5 +1,6 @@ """Tag app filters.""" from django_filters import rest_framework as filters +from establishment.models import EstablishmentType from tag import models @@ -18,16 +19,9 @@ class TagCategoryFilterSet(filters.FilterSet): type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES, method='filter_by_type') - # Establishment type choices - RESTAURANT = 'restaurant' - - ESTABLISHMENT_TYPE_CHOICES = ( - (RESTAURANT, 'restaurant'), - ) - - establishment_type = filters.MultipleChoiceFilter( - choices=ESTABLISHMENT_TYPE_CHOICES, - method='filter_by_establishment_type') + establishment_type = filters.ChoiceFilter( + choices=EstablishmentType.INDEX_NAME_TYPES, + method='by_establishment_type') class Meta: """Meta class.""" @@ -44,5 +38,5 @@ class TagCategoryFilterSet(filters.FilterSet): return queryset # todo: filter by establishment type - def filter_by_establishment_type(self, queryset, name, value): - return queryset.for_establishments() + def by_establishment_type(self, queryset, name, value): + return queryset.by_establishment_type(value) diff --git a/apps/tag/models.py b/apps/tag/models.py index 4fa04f8e..d8d32639 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -45,6 +45,10 @@ class TagCategoryQuerySet(models.QuerySet): return self.filter(models.Q(establishment_types__isnull=False) | models.Q(establishment_subtypes__isnull=False)) + def by_establishment_type(self, index_name): + """Filter by establishment type index name.""" + return self.filter(establishment_types__index_name=index_name) + def with_tags(self, switcher=True): """Filter by existing tags.""" return self.filter(tags__isnull=not switcher) diff --git a/apps/tag/views.py b/apps/tag/views.py index 622ec849..ea83f3d5 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -20,5 +20,6 @@ class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): filterset_class = filters.TagCategoryFilterSet pagination_class = None permission_classes = (permissions.AllowAny, ) - queryset = models.TagCategory.objects.with_tags().with_base_related() + queryset = models.TagCategory.objects.with_tags().with_base_related().\ + distinct() serializer_class = serializers.TagCategoryBaseSerializer From 7be7315cef145ced8352e93a456aa70e57b2fad8 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 18 Oct 2019 18:00:57 +0300 Subject: [PATCH 23/25] added filters and endpoint to get winery list --- apps/establishment/filters.py | 12 ++++++ .../0038_establishmenttype_index_name.py | 5 ++- .../0039_establishmentsubtype_index_name.py | 35 +++++++++++++++++ apps/establishment/models.py | 38 +++++++++++++++++++ apps/establishment/urls/common.py | 1 + apps/establishment/views/web.py | 11 ++++++ 6 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 apps/establishment/migrations/0039_establishmentsubtype_index_name.py diff --git a/apps/establishment/filters.py b/apps/establishment/filters.py index 13d951b6..20ece644 100644 --- a/apps/establishment/filters.py +++ b/apps/establishment/filters.py @@ -10,6 +10,10 @@ class EstablishmentFilter(filters.FilterSet): tag_id = filters.NumberFilter(field_name='tags__metadata__id',) award_id = filters.NumberFilter(field_name='awards__id',) search = filters.CharFilter(method='search_text') + est_type = filters.ChoiceFilter(choices=models.EstablishmentType.INDEX_NAME_TYPES, + method='by_type') + est_subtype = filters.ChoiceFilter(choices=models.EstablishmentSubType.INDEX_NAME_TYPES, + method='by_subtype') class Meta: """Meta class.""" @@ -19,6 +23,8 @@ class EstablishmentFilter(filters.FilterSet): 'tag_id', 'award_id', 'search', + 'est_type', + 'est_subtype', ) def search_text(self, queryset, name, value): @@ -27,6 +33,12 @@ class EstablishmentFilter(filters.FilterSet): return queryset.search(value, locale=self.request.locale) return queryset + def by_type(self, queryset, name, value): + return queryset.by_type(value) + + def by_subtype(self, queryset, name, value): + return queryset.by_subtype(value) + class EstablishmentTypeTagFilter(filters.FilterSet): """Establishment tag filter set.""" diff --git a/apps/establishment/migrations/0038_establishmenttype_index_name.py b/apps/establishment/migrations/0038_establishmenttype_index_name.py index 657dbe42..5f9d5879 100644 --- a/apps/establishment/migrations/0038_establishmenttype_index_name.py +++ b/apps/establishment/migrations/0038_establishmenttype_index_name.py @@ -3,8 +3,9 @@ from django.db import migrations, models -def fill_establishment_type(apps, schemaeditor): - import ipdb; ipdb.set_trace() +def fill_establishment_type(apps, schema_editor): + # We can't import the Person model directly as it may be a newer + # version than this migration expects. We use the historical version. EstablishmentType = apps.get_model('establishment', 'EstablishmentType') for n, et in enumerate(EstablishmentType.objects.all()): et.index_name = f'Type {n}' diff --git a/apps/establishment/migrations/0039_establishmentsubtype_index_name.py b/apps/establishment/migrations/0039_establishmentsubtype_index_name.py new file mode 100644 index 00000000..5473600a --- /dev/null +++ b/apps/establishment/migrations/0039_establishmentsubtype_index_name.py @@ -0,0 +1,35 @@ +# Generated by Django 2.2.4 on 2019-10-18 13:47 + +from django.db import migrations, models + + +def fill_establishment_subtype(apps, schema_editor): + # We can't import the Person model directly as it may be a newer + # version than this migration expects. We use the historical version. + EstablishmentSubType = apps.get_model('establishment', 'EstablishmentSubType') + for n, et in enumerate(EstablishmentSubType.objects.all()): + et.index_name = f'Type {n}' + et.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0038_establishmenttype_index_name'), + ] + + operations = [ + migrations.AddField( + model_name='establishmentsubtype', + name='index_name', + field=models.CharField(blank=True, db_index=True, max_length=50, null=True, unique=True, default=None, verbose_name='Index name'), + ), + migrations.RunPython(fill_establishment_subtype), + migrations.AlterField( + model_name='establishmentsubtype', + name='index_name', + field=models.CharField(choices=[('winery', 'Winery'), ], db_index=True, max_length=50, + unique=True, verbose_name='Index name'), + ), + + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 7466414c..d69c0395 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -68,8 +68,18 @@ class EstablishmentSubTypeManager(models.Manager): class EstablishmentSubType(ProjectBaseMixin, TranslatedFieldsMixin): """Establishment type model.""" + # INDEX NAME CHOICES + WINERY = 'winery' + + INDEX_NAME_TYPES = ( + (WINERY, _('Winery')), + ) + name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), help_text='{"en-GB":"some text"}') + index_name = models.CharField(max_length=50, choices=INDEX_NAME_TYPES, + unique=True, db_index=True, + verbose_name=_('Index name')) establishment_type = models.ForeignKey(EstablishmentType, on_delete=models.CASCADE, verbose_name=_('Type')) @@ -104,6 +114,9 @@ class EstablishmentQuerySet(models.QuerySet): 'phones').\ prefetch_actual_employees() + def with_type_related(self): + return self.prefetch_related('establishment_subtypes') + def search(self, value, locale=None): """Search text in JSON fields.""" if locale is not None: @@ -251,6 +264,31 @@ class EstablishmentQuerySet(models.QuerySet): kwargs = {unit: radius} return self.filter(address__coordinates__distance_lte=(center, DistanceMeasure(**kwargs))) + def artisans(self): + """Return artisans.""" + return self.filter(establishment_type__index_name=EstablishmentType.ARTISAN) + + def producers(self): + """Return producers.""" + return self.filter(establishment_type__index_name=EstablishmentType.PRODUCER) + + def restaurants(self): + """Return restaurants.""" + return self.filter(establishment_type__index_name=EstablishmentType.RESTAURANT) + + def wineries(self): + """Return wineries.""" + return self.producers().filter( + establishment_subtypes__index_name=EstablishmentSubType.WINERY) + + def by_type(self, value): + """Return QuerySet with type by value.""" + return self.filter(establishment_type__index_name=value) + + def by_subtype(self, value): + """Return QuerySet with subtype by value.""" + return self.filter(establishment_subtypes__index_name=value) + class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): """Establishment model.""" diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 5d7df146..8d9453c1 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -9,6 +9,7 @@ urlpatterns = [ path('', views.EstablishmentListView.as_view(), name='list'), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), name='recent-reviews'), + # path('wineries/', views.WineriesListView.as_view(), name='wineries-list'), path('slug//', views.EstablishmentRetrieveView.as_view(), name='detail'), path('slug//similar/', views.EstablishmentSimilarListView.as_view(), name='similar'), path('slug//comments/', views.EstablishmentCommentListView.as_view(), name='list-comments'), diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index f164ec73..cd83fed5 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -174,3 +174,14 @@ class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIVi return qs.by_distance_from_point(**{k: v for k, v in filter_kwargs.items() if v is not None}) return qs + + +# Wineries +# todo: find out about difference between subtypes data +# class WineriesListView(EstablishmentListView): +# """Return list establishments with type Wineries""" +# +# def get_queryset(self): +# """Overridden get_queryset method.""" +# qs = super(WineriesListView, self).get_queryset() +# return qs.with_type_related().wineries() From 21e3f76f5a24847490894aefbb206f41dc4c9658 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 18 Oct 2019 18:02:24 +0300 Subject: [PATCH 24/25] Backoffice Tag&TagCategory --- .../tag/migrations/0003_auto_20191018_0758.py | 19 +++ apps/tag/models.py | 6 +- apps/tag/serializers.py | 104 ++++++++++++++++- apps/tag/urls/back.py | 11 +- apps/tag/views.py | 108 ++++++++++++++++-- .../migrations/0004_auto_20191018_0832.py | 18 +++ apps/translation/models.py | 2 +- apps/utils/exceptions.py | 23 +++- project/urls/back.py | 10 +- 9 files changed, 272 insertions(+), 29 deletions(-) create mode 100644 apps/tag/migrations/0003_auto_20191018_0758.py create mode 100644 apps/translation/migrations/0004_auto_20191018_0832.py diff --git a/apps/tag/migrations/0003_auto_20191018_0758.py b/apps/tag/migrations/0003_auto_20191018_0758.py new file mode 100644 index 00000000..3814d05a --- /dev/null +++ b/apps/tag/migrations/0003_auto_20191018_0758.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-10-18 07:58 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0002_auto_20191009_1408'), + ] + + operations = [ + migrations.AlterField( + model_name='tag', + name='category', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='tag.TagCategory', verbose_name='Category'), + ), + ] diff --git a/apps/tag/models.py b/apps/tag/models.py index d8d32639..85d86e74 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -11,7 +11,7 @@ class Tag(TranslatedFieldsMixin, models.Model): label = TJSONField(blank=True, null=True, default=None, verbose_name=_('label'), help_text='{"en-GB":"some text"}') - category = models.ForeignKey('TagCategory', on_delete=models.PROTECT, + category = models.ForeignKey('TagCategory', on_delete=models.CASCADE, null=True, related_name='tags', verbose_name=_('Category')) @@ -36,6 +36,10 @@ class TagCategoryQuerySet(models.QuerySet): """Select related objects.""" return self.prefetch_related('tags') + def with_extended_related(self): + """Select related objects.""" + return self.select_related('country') + def for_news(self): """Select tag categories for news.""" return self.filter(news_types__isnull=True) diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index e4ecf25d..8c994d8d 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -1,6 +1,11 @@ """Tag serializers.""" from rest_framework import serializers +from establishment.models import (Establishment, EstablishmentType, + EstablishmentSubType) +from news.models import News, NewsType from tag import models +from utils.exceptions import (ObjectAlreadyAdded, BindingObjectNotFound, + RemovedBindingObjectNotFound) from utils.serializers import TranslatedField @@ -49,14 +54,109 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer): class TagCategoryBackOfficeDetailSerializer(TagCategoryBaseSerializer): + """Tag Category detail serializer for back-office users.""" country_translated = TranslatedField(source='country.name_translated') - class Meta(TagBaseSerializer.Meta): + class Meta(TagCategoryBaseSerializer.Meta): """Meta class.""" fields = TagCategoryBaseSerializer.Meta.fields + ( - 'news_types', + 'label', 'country', 'country_translated', ) + + +class TagBindObjectSerializer(serializers.Serializer): + """Serializer for binding tag category and objects""" + + ESTABLISHMENT = 'establishment' + NEWS = 'news' + + TYPE_CHOICES = ( + (ESTABLISHMENT, 'Establishment type'), + (NEWS, 'News type'), + ) + + type = serializers.ChoiceField(TYPE_CHOICES) + object_id = serializers.IntegerField() + + def validate(self, attrs): + obj_type = attrs.get('type') + obj_id = attrs.get('object_id') + request = self.context.get('request') + view = self.context.get('view') + tag = view.get_object() + attrs['tag'] = tag + if obj_type == self.ESTABLISHMENT: + establishment = Establishment.objects.filter(pk=obj_id).first() + if not establishment: + raise BindingObjectNotFound() + if request.method == 'POST' and tag.establishments.filter( + pk=establishment.pk).exists(): + raise ObjectAlreadyAdded() + if request.method == 'DELETE' and not tag.establishments.filter( + pk=establishment.pk).exists(): + raise RemovedBindingObjectNotFound() + attrs['related_object'] = establishment + elif obj_type == self.NEWS: + news = News.objects.filter(pk=obj_id).first() + if not news: + raise BindingObjectNotFound() + if request.method == 'POST' and tag.news.filter(pk=news.pk).exists(): + raise ObjectAlreadyAdded() + if request.method == 'DELETE' and not tag.news.filter( + pk=news.pk).exists(): + raise RemovedBindingObjectNotFound() + attrs['related_object'] = news + return attrs + + +class TagCategoryBindObjectSerializer(serializers.Serializer): + """Serializer for binding tag category and objects""" + + ESTABLISHMENT_TYPE = 'establishment_type' + NEWS_TYPE = 'news_type' + + TYPE_CHOICES = ( + (ESTABLISHMENT_TYPE, 'Establishment type'), + (NEWS_TYPE, 'News type'), + ) + + type = serializers.ChoiceField(TYPE_CHOICES) + object_id = serializers.IntegerField() + + def validate(self, attrs): + obj_type = attrs.get('type') + obj_id = attrs.get('object_id') + view = self.context.get('view') + tag_category = view.get_object() + attrs['tag_category'] = tag_category + request = self.context.get('request') + + if obj_type == self.ESTABLISHMENT_TYPE: + establishment_type = EstablishmentType.objects.filter(pk=obj_id).\ + first() + if not establishment_type: + raise BindingObjectNotFound() + if request.method == 'POST' and tag_category.establishment_types.\ + filter(pk=establishment_type.pk).exists(): + raise ObjectAlreadyAdded() + if request.method == 'DELETE' and not tag_category.\ + establishment_types.filter(pk=establishment_type.pk).\ + exists(): + raise RemovedBindingObjectNotFound() + attrs['related_object'] = establishment_type + elif obj_type == self.NEWS: + news_type = NewsType.objects.filter(pk=obj_id).first() + if not news_type: + raise BindingObjectNotFound() + if request.method == 'POST' and tag_category.news_types.\ + filter(pk=news_type.pk).exists(): + raise ObjectAlreadyAdded() + if request.method == 'DELETE' and not tag_category.news_types.\ + filter(pk=news_type.pk).exists(): + raise RemovedBindingObjectNotFound() + attrs['related_object'] = news_type + return attrs diff --git a/apps/tag/urls/back.py b/apps/tag/urls/back.py index 9f03bb45..03733297 100644 --- a/apps/tag/urls/back.py +++ b/apps/tag/urls/back.py @@ -1,16 +1,11 @@ """Urlconf for app tag.""" -from django.urls import path from rest_framework.routers import SimpleRouter from tag import views app_name = 'tag' router = SimpleRouter() -router.register(r'', views.TagViewSet) +router.register(r'categories', views.TagCategoryBackOfficeViewSet) +router.register(r'', views.TagBackOfficeViewSet) - -urlpatterns = [ - path('category/', views.TagCategoryListCreateView.as_view(), name='category-list-create'), -] - -urlpatterns += router.urls +urlpatterns = router.urls diff --git a/apps/tag/views.py b/apps/tag/views.py index ea83f3d5..2a0ff0f5 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -1,19 +1,12 @@ """Tag views.""" -from rest_framework import viewsets, mixins +from rest_framework import viewsets, mixins, status +from rest_framework.decorators import action +from rest_framework.response import Response from tag import filters, models, serializers from rest_framework import permissions -class TagViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, - mixins.UpdateModelMixin, mixins.DestroyModelMixin, - viewsets.GenericViewSet): - """List/create tag view.""" - - pagination_class = None - queryset = models.Tag.objects.all() - serializer_class = serializers.TagBackOfficeSerializer - - +# User`s views & viewsets class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ViewSet for TagCategory model.""" @@ -23,3 +16,96 @@ class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): queryset = models.TagCategory.objects.with_tags().with_base_related().\ distinct() serializer_class = serializers.TagCategoryBaseSerializer + + +# BackOffice user`s views & viewsets +class BindObjectMixin: + """Bind object mixin.""" + + def get_serializer_class(self): + if self.action == 'bind_object': + return self.bind_object_serializer_class + return self.serializer_class + + def perform_binding(self, serializer): + raise NotImplemented + + def perform_unbinding(self, serializer): + raise NotImplemented + + @action(methods=['post', 'delete'], detail=True, url_path='bind-object') + def bind_object(self, request, pk=None): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + if request.method == 'POST': + self.perform_binding(serializer) + return Response(serializer.data, status=status.HTTP_201_CREATED) + elif request.method == 'DELETE': + self.perform_unbinding(serializer) + return Response(status=status.HTTP_204_NO_CONTENT) + + +class TagBackOfficeViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, + mixins.UpdateModelMixin, mixins.DestroyModelMixin, + BindObjectMixin, viewsets.GenericViewSet): + """List/create tag view.""" + + pagination_class = None + permission_classes = (permissions.IsAuthenticated, ) + queryset = models.Tag.objects.all() + serializer_class = serializers.TagBackOfficeSerializer + bind_object_serializer_class = serializers.TagBindObjectSerializer + + def perform_binding(self, serializer): + data = serializer.validated_data + tag = data.pop('tag') + obj_type = data.get('type') + related_object = data.get('related_object') + if obj_type == self.bind_object_serializer_class.ESTABLISHMENT: + tag.establishments.add(related_object) + elif obj_type == self.bind_object_serializer_class.NEWS: + tag.news.add(related_object) + + def perform_unbinding(self, serializer): + data = serializer.validated_data + tag = data.pop('tag') + obj_type = data.get('type') + related_object = data.get('related_object') + if obj_type == self.bind_object_serializer_class.ESTABLISHMENT: + tag.establishments.remove(related_object) + elif obj_type == self.bind_object_serializer_class.NEWS: + tag.news.remove(related_object) + + +class TagCategoryBackOfficeViewSet(mixins.CreateModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + mixins.RetrieveModelMixin, + BindObjectMixin, + TagCategoryViewSet): + """ViewSet for TagCategory model for BackOffice users.""" + + permission_classes = (permissions.IsAuthenticated, ) + queryset = TagCategoryViewSet.queryset.with_extended_related() + serializer_class = serializers.TagCategoryBackOfficeDetailSerializer + bind_object_serializer_class = serializers.TagCategoryBindObjectSerializer + + def perform_binding(self, serializer): + data = serializer.validated_data + tag_category = data.pop('tag_category') + obj_type = data.get('type') + related_object = data.get('related_object') + if obj_type == self.bind_object_serializer_class.ESTABLISHMENT_TYPE: + tag_category.establishment_types.add(related_object) + elif obj_type == self.bind_object_serializer_class.NEWS_TYPE: + tag_category.news_types.add(related_object) + + def perform_unbinding(self, serializer): + data = serializer.validated_data + tag_category = data.pop('tag_category') + obj_type = data.get('type') + related_object = data.get('related_object') + if obj_type == self.bind_object_serializer_class.ESTABLISHMENT_TYPE: + tag_category.establishment_types.remove(related_object) + elif obj_type == self.bind_object_serializer_class.NEWS_TYPE: + tag_category.news_types.remove(related_object) diff --git a/apps/translation/migrations/0004_auto_20191018_0832.py b/apps/translation/migrations/0004_auto_20191018_0832.py new file mode 100644 index 00000000..d2d26a2b --- /dev/null +++ b/apps/translation/migrations/0004_auto_20191018_0832.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-10-18 08:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('translation', '0003_auto_20190901_1032'), + ] + + operations = [ + migrations.AlterField( + model_name='language', + name='locale', + field=models.CharField(max_length=10, unique=True, verbose_name='Locale identifier'), + ), + ] diff --git a/apps/translation/models.py b/apps/translation/models.py index 42530965..bc9fbfbf 100644 --- a/apps/translation/models.py +++ b/apps/translation/models.py @@ -22,7 +22,7 @@ class Language(models.Model): title = models.CharField(max_length=255, verbose_name=_('Language title')) - locale = models.CharField(max_length=10, + locale = models.CharField(max_length=10, unique=True, verbose_name=_('Locale identifier')) objects = LanguageQuerySet.as_manager() diff --git a/apps/utils/exceptions.py b/apps/utils/exceptions.py index 440f4ed4..37786ce7 100644 --- a/apps/utils/exceptions.py +++ b/apps/utils/exceptions.py @@ -1,5 +1,5 @@ from django.utils.translation import gettext_lazy as _ -from rest_framework import exceptions, status +from rest_framework import exceptions, serializers, status class ProjectBaseException(exceptions.APIException): @@ -142,3 +142,24 @@ class PasswordResetRequestExistedError(exceptions.APIException): """ status_code = status.HTTP_400_BAD_REQUEST default_detail = _('Password reset request is already exists and valid.') + + +class ObjectAlreadyAdded(serializers.ValidationError): + """ + The exception must be thrown if the object has already been added to the + list. + """ + + default_detail = _('Object has already been added.') + + +class BindingObjectNotFound(serializers.ValidationError): + """The exception must be thrown if the object not found.""" + + default_detail = _('Binding object not found.') + + +class RemovedBindingObjectNotFound(serializers.ValidationError): + """The exception must be thrown if the object not found.""" + + default_detail = _('Removed binding object not found.') diff --git a/project/urls/back.py b/project/urls/back.py index 5d221932..206d359c 100644 --- a/project/urls/back.py +++ b/project/urls/back.py @@ -3,11 +3,11 @@ from django.urls import path, include app_name = 'back' urlpatterns = [ - path('gallery/', include(('gallery.urls', 'gallery'), namespace='gallery')), - path('establishments/', include('establishment.urls.back')), - path('location/', include('location.urls.back')), - path('news/', include('news.urls.back')), - # path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')), path('account/', include('account.urls.back')), path('comment/', include('comment.urls.back')), + path('establishments/', include('establishment.urls.back')), + path('gallery/', include(('gallery.urls', 'gallery'), namespace='gallery')), + path('location/', include('location.urls.back')), + path('news/', include('news.urls.back')), + path('tags/', include(('tag.urls.back', 'tag'), namespace='tag')), ] From 1cd586662ac52e85ce268b5d2dc5e48989af8751 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Mon, 21 Oct 2019 10:12:30 +0300 Subject: [PATCH 25/25] fix tagcategory binding serializer --- apps/tag/serializers.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index 8c994d8d..6ee55c84 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -83,12 +83,15 @@ class TagBindObjectSerializer(serializers.Serializer): object_id = serializers.IntegerField() def validate(self, attrs): + view = self.context.get('view') + request = self.context.get('request') + obj_type = attrs.get('type') obj_id = attrs.get('object_id') - request = self.context.get('request') - view = self.context.get('view') + tag = view.get_object() attrs['tag'] = tag + if obj_type == self.ESTABLISHMENT: establishment = Establishment.objects.filter(pk=obj_id).first() if not establishment: @@ -128,12 +131,14 @@ class TagCategoryBindObjectSerializer(serializers.Serializer): object_id = serializers.IntegerField() def validate(self, attrs): + view = self.context.get('view') + request = self.context.get('request') + obj_type = attrs.get('type') obj_id = attrs.get('object_id') - view = self.context.get('view') + tag_category = view.get_object() attrs['tag_category'] = tag_category - request = self.context.get('request') if obj_type == self.ESTABLISHMENT_TYPE: establishment_type = EstablishmentType.objects.filter(pk=obj_id).\ @@ -148,7 +153,7 @@ class TagCategoryBindObjectSerializer(serializers.Serializer): exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = establishment_type - elif obj_type == self.NEWS: + elif obj_type == self.NEWS_TYPE: news_type = NewsType.objects.filter(pk=obj_id).first() if not news_type: raise BindingObjectNotFound()