From b94e933cb1bfaeb2ac28867f0b672bbd43a0c200 Mon Sep 17 00:00:00 2001 From: dormantman Date: Thu, 30 Jan 2020 20:58:45 +0300 Subject: [PATCH] Added migration --- .../migrations/0089_auto_20200130_1758.py | 140 ++++++++++++++++++ apps/establishment/models.py | 7 +- apps/establishment/serializers/common.py | 87 ++--------- apps/establishment/views/back.py | 71 +++++++-- 4 files changed, 217 insertions(+), 88 deletions(-) create mode 100644 apps/establishment/migrations/0089_auto_20200130_1758.py diff --git a/apps/establishment/migrations/0089_auto_20200130_1758.py b/apps/establishment/migrations/0089_auto_20200130_1758.py new file mode 100644 index 00000000..b9ac43c9 --- /dev/null +++ b/apps/establishment/migrations/0089_auto_20200130_1758.py @@ -0,0 +1,140 @@ +# Generated by Django 2.2.7 on 2020-01-30 17:58 + +from django.conf import settings +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('gallery', '0008_merge_20191212_0752'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('establishment', '0088_merge_20200130_1318'), + ] + + operations = [ + migrations.CreateModel( + name='MenuGallery', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_main', models.BooleanField(default=False, verbose_name='Is the main image')), + ('image', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='menu_gallery', to='gallery.Image', verbose_name='image')), + ], + options={ + 'verbose_name': 'menu gallery', + 'verbose_name_plural': 'menu galleries', + }, + ), + migrations.CreateModel( + name='MenuUploads', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('title', models.CharField(default='', max_length=255, verbose_name='title')), + ('file', models.FileField(upload_to='', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=('doc', 'docx', 'pdf'))], verbose_name='File')), + ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menuuploads_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')), + ], + options={ + 'verbose_name': 'menu upload', + 'verbose_name_plural': 'menu uploads', + }, + ), + migrations.RemoveField( + model_name='menufiles', + name='created_by', + ), + migrations.RemoveField( + model_name='menufiles', + name='modified_by', + ), + migrations.RemoveField( + model_name='menu', + name='average_desert_price', + ), + migrations.RemoveField( + model_name='menu', + name='average_main_dish_price', + ), + migrations.RemoveField( + model_name='menu', + name='average_starter_price', + ), + migrations.RemoveField( + model_name='menu', + name='dishes', + ), + migrations.RemoveField( + model_name='menu', + name='highest_price', + ), + migrations.RemoveField( + model_name='menu', + name='lowest_price', + ), + migrations.RemoveField( + model_name='menu', + name='name', + ), + migrations.RemoveField( + model_name='menu', + name='nb_wine', + ), + migrations.RemoveField( + model_name='menu', + name='price', + ), + migrations.RemoveField( + model_name='menu', + name='price_max_by_glass', + ), + migrations.RemoveField( + model_name='menu', + name='price_min_by_glass', + ), + migrations.RemoveField( + model_name='menu', + name='renewal_per_year', + ), + migrations.RemoveField( + model_name='menu', + name='served_by_glasses', + ), + migrations.RemoveField( + model_name='menu', + name='uploads', + ), + migrations.AlterField( + model_name='menu', + name='schedule', + field=models.ManyToManyField(blank=True, related_name='menus', to='timetable.Timetable', verbose_name='Establishment schedule'), + ), + migrations.DeleteModel( + name='MenuDish', + ), + migrations.DeleteModel( + name='MenuFiles', + ), + migrations.AddField( + model_name='menuuploads', + name='menu', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='menu_uploads', to='establishment.Menu', verbose_name='menu'), + ), + migrations.AddField( + model_name='menuuploads', + name='modified_by', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menuuploads_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by'), + ), + migrations.AddField( + model_name='menugallery', + name='menu', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='menu_gallery', to='establishment.Menu', verbose_name='menu'), + ), + migrations.AlterUniqueTogether( + name='menugallery', + unique_together={('menu', 'image'), ('menu', 'is_main')}, + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index f86717ed..46bc671c 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -14,19 +14,20 @@ from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.indexes import GinIndex from django.contrib.postgres.search import TrigramSimilarity from django.core.exceptions import ValidationError -from django.core.validators import MaxValueValidator, MinValueValidator, FileExtensionValidator +from django.core.validators import FileExtensionValidator, MaxValueValidator, MinValueValidator from django.db import models from django.db.models import Case, ExpressionWrapper, F, Prefetch, Q, Subquery, When from django.shortcuts import get_object_or_404 from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from phonenumber_field.modelfields import PhoneNumberField +from timezone_field import TimeZoneField + from location.models import Address from main.models import Award, Currency -from phonenumber_field.modelfields import PhoneNumberField from review.models import Review from tag.models import Tag from timetable.models import Timetable -from timezone_field import TimeZoneField from utils.methods import transform_into_readable_str from utils.models import ( BaseAttributes, FavoritesMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin, ProjectBaseMixin, diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 68c092c6..3fb7a152 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -2,7 +2,6 @@ import logging from django.conf import settings -from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext_lazy as _ from phonenumber_field.phonenumber import to_python as str_to_phonenumber from rest_framework import serializers @@ -73,89 +72,31 @@ class PlateSerializer(ProjectModelSerializer): ] -class MenuDishSerializer(ProjectModelSerializer): - class Meta: - model = models.MenuDish - fields = [ - 'id', - 'name', - 'category', - 'price', - 'signature' - ] - - -class MenuFilesSerializers(ProjectModelSerializer): - menu_id = serializers.IntegerField(write_only=True) - - class Meta: - model = models.MenuFiles - fields = [ - 'id', - 'name', - 'type', - 'file', - 'menu_id' - ] - - def create(self, validated_data): - menu_id = validated_data.pop('menu_id') - menu = get_object_or_404(models.Menu, pk=menu_id) - instance = models.MenuFiles.objects.create(**validated_data) - menu.uploads.add(instance) - return instance - - class MenuSerializers(ProjectModelSerializer): - name = serializers.CharField() - establishment_id = serializers.PrimaryKeyRelatedField(queryset=models.Establishment.objects.all()) - establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') - price = serializers.IntegerField(required=False) - drinks_included = serializers.BooleanField(source='is_drinks_included', required=False) - schedules = ScheduleRUDSerializer(many=True, allow_null=True, required=False) - uploads = MenuFilesSerializers(many=True, read_only=True) + plates = PlateSerializer(read_only=True, many=True, source='plate_set') + category_translated = serializers.CharField(read_only=True) class Meta: model = models.Menu fields = [ 'id', - 'name', - 'establishment_id', - 'establishment_slug', - 'price', - 'drinks_included', - 'schedules', - 'uploads', + 'category', + 'category_translated', + 'plates', + 'establishment' ] - def create(self, validated_data): - validated_data['establishment'] = validated_data.pop('establishment_id') - instance = models.Menu.objects.create(**validated_data) - return instance - class MenuRUDSerializers(ProjectModelSerializer): - name = serializers.CharField() - establishment_id = serializers.PrimaryKeyRelatedField(read_only=True) - establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') - price = serializers.IntegerField(required=False) - drinks_included = serializers.BooleanField(source='is_drinks_included', required=False) - schedules = ScheduleRUDSerializer(many=True, allow_null=True, required=False) - uploads = MenuFilesSerializers(many=True) + plates = PlateSerializer(read_only=True, many=True, source='plate_set') - class Meta(MenuSerializers.Meta): - """Overridden Meta class.""" - fields = MenuSerializers.Meta.fields + [ - 'average_starter_price', - 'average_main_dish_price', - 'average_desert_price', - 'renewal_per_year', - 'nb_wine', - 'lowest_price', - 'highest_price', - 'served_by_glasses', - 'price_min_by_glass', - 'price_max_by_glass', + class Meta: + model = models.Menu + fields = [ + 'id', + 'category', + 'plates', + 'establishment' ] diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index d54f3702..39a7a54a 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -3,7 +3,7 @@ from django.db.models.query_utils import Q from django.http import Http404 from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend -from rest_framework import generics, status +from rest_framework import generics, status, response from rest_framework.response import Response from account.models import User @@ -568,34 +568,81 @@ class EstablishmentAdminView(generics.ListAPIView): return User.objects.establishment_admin(establishment).distinct() -class MenuDishesListView(generics.ListAPIView): +class MenuDishesListCreateView(generics.ListCreateAPIView): """Menu (dessert, main_course, starter) list create view.""" serializer_class = serializers.MenuDishesSerializer - queryset = models.Menu.objects.with_dishes() - filter_class = filters.MenuDishesBackFilter + queryset = models.Menu.objects.with_schedule_plates_establishment().dishes().distinct() permission_classes = get_permission_classes( IsEstablishmentManager, IsEstablishmentAdministrator ) + filter_class = filters.MenuDishesBackFilter -class MenuDishesRUDView(MenuRUDMixinViews, generics.RetrieveUpdateDestroyAPIView): +class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView): """Menu (dessert, main_course, starter) RUD view.""" - lookup_field = None serializer_class = serializers.MenuDishesRUDSerializers - queryset = models.Menu.objects.with_dishes() + queryset = models.Menu.objects.dishes().distinct() permission_classes = get_permission_classes( IsEstablishmentManager, IsEstablishmentAdministrator ) -class MenuDishesCreateView(generics.CreateAPIView): - """Menu (dessert, main_course, starter) list create view.""" - serializer_class = serializers.MenuDishesCreateSerializer - queryset = models.MenuDish.objects.all() - filter_class = filters.MenuDishesBackFilter +class MenuGalleryListView(generics.ListAPIView): + """Resource for returning gallery for menu for back-office users.""" + serializer_class = serializers.ImageBaseSerializer permission_classes = get_permission_classes( IsEstablishmentManager, IsEstablishmentAdministrator ) + queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() + + def get_object(self): + """Override get_object method.""" + qs = super(MenuGalleryListView, self).get_queryset() + menu = get_object_or_404(qs, pk=self.kwargs.get('pk')) + + # May raise a permission denied + # self.check_object_permissions(self.request, menu) + + return menu + + def get_queryset(self): + """Override get_queryset method.""" + return self.get_object().crop_gallery + + +class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin): + """Resource for a create gallery for menu for back-office users.""" + serializer_class = serializers.MenuGallerySerializer + permission_classes = get_permission_classes( + IsEstablishmentManager, + IsEstablishmentAdministrator + ) + + def get_queryset(self): + """Override get_queryset method.""" + qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() + return qs + + def create(self, request, *args, **kwargs): + _ = super().create(request, *args, **kwargs) + news_qs = self.filter_queryset(self.get_queryset()) + return response.Response( + data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data + ) + + def get_object(self): + """ + Returns the object the view is displaying. + """ + menu_qs = self.filter_queryset(self.get_queryset()) + + menu = get_object_or_404(menu_qs, pk=self.kwargs.get('pk')) + gallery = get_object_or_404(menu.menu_gallery, image_id=self.kwargs.get('image_id')) + + # May raise a permission denied + self.check_object_permissions(self.request, gallery) + + return gallery