Added menu upload files

This commit is contained in:
dormantman 2020-01-28 18:29:02 +03:00
parent 2b0663b702
commit e067e8e793
7 changed files with 210 additions and 154 deletions

View File

@ -30,10 +30,13 @@ from main.models import Award, Currency
from review.models import Review
from tag.models import Tag
from utils.methods import transform_into_readable_str
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
TranslatedFieldsMixin, BaseAttributes, GalleryMixin,
IntermediateGalleryModelMixin, HasTagsMixin,
FavoritesMixin, TypeDefaultImageMixin)
from utils.models import (
ProjectBaseMixin, TJSONField, URLImageMixin,
TranslatedFieldsMixin, BaseAttributes, GalleryMixin,
IntermediateGalleryModelMixin, HasTagsMixin,
FavoritesMixin, TypeDefaultImageMixin, FileMixin,
ImageMixin,
)
# todo: establishment type&subtypes check
@ -1272,6 +1275,7 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes):
STR_FIELD_NAME = 'category'
name = models.CharField(_('name'), max_length=255, default='')
category = TJSONField(
blank=True, null=True, default=None, verbose_name=_('category'),
help_text='{"en-GB":"some text"}')
@ -1282,9 +1286,14 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes):
schedule = models.ManyToManyField(
to='timetable.Timetable',
blank=True,
verbose_name=_('Establishment schedule'),
related_name='menus',
verbose_name=_('Menu schedule'),
)
uploads = models.ManyToManyField(
to='MenuFiles',
blank=True,
verbose_name=_('Menu files'),
)
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
objects = MenuQuerySet.as_manager()
@ -1295,43 +1304,11 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes):
ordering = ('-created',)
class MenuGallery(IntermediateGalleryModelMixin):
menu = models.ForeignKey(
Menu,
null=True,
related_name='menu_gallery',
on_delete=models.CASCADE,
verbose_name=_('menu'),
)
image = models.ForeignKey(
'gallery.Image',
null=True,
related_name='menu_gallery',
on_delete=models.CASCADE,
verbose_name=_('image'),
)
class Meta:
"""Meta class."""
verbose_name = _('menu gallery')
verbose_name_plural = _('menu galleries')
unique_together = (('menu', 'is_main'), ('menu', 'image'))
class MenuUploads(BaseAttributes):
class MenuFiles(FileMixin, BaseAttributes):
"""Menu files"""
menu = models.ForeignKey(
Menu,
verbose_name=_('menu'),
on_delete=models.CASCADE,
related_name='menu_uploads',
)
title = models.CharField(_('title'), max_length=255, default='')
file = models.FileField(
_('File'),
validators=[FileExtensionValidator(allowed_extensions=('doc', 'docx', 'pdf')), ],
)
name = models.CharField(_('name'), max_length=255, default='')
type = models.CharField(_('type'), max_length=65, default='')
class Meta:
verbose_name = _('menu upload')

View File

@ -639,50 +639,50 @@ class MenuDishesRUDSerializers(ProjectModelSerializer):
]
class MenuGallerySerializer(serializers.ModelSerializer):
"""Serializer class for model MenuGallery."""
class Meta:
"""Meta class"""
model = models.MenuGallery
fields = [
'id',
'is_main',
]
@property
def request_kwargs(self):
"""Get url kwargs from request."""
return self.context.get('request').parser_context.get('kwargs')
def create(self, validated_data):
menu_pk = self.request_kwargs.get('pk')
image_id = self.request_kwargs.get('image_id')
qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk)
instance = qs.first()
if instance:
qs.update(**validated_data)
return instance
return super().create(validated_data)
def validate(self, attrs):
"""Override validate method."""
menu_pk = self.request_kwargs.get('pk')
image_id = self.request_kwargs.get('image_id')
menu_qs = models.Menu.objects.filter(pk=menu_pk)
image_qs = Image.objects.filter(id=image_id)
if not menu_qs.exists():
raise serializers.ValidationError({'detail': _('Menu not found')})
if not image_qs.exists():
raise serializers.ValidationError({'detail': _('Image not found')})
menu = menu_qs.first()
image = image_qs.first()
attrs['menu'] = menu
attrs['image'] = image
return attrs
# class MenuGallerySerializer(serializers.ModelSerializer):
# """Serializer class for model MenuGallery."""
#
# class Meta:
# """Meta class"""
#
# model = models.MenuGallery
# fields = [
# 'id',
# 'is_main',
# ]
#
# @property
# def request_kwargs(self):
# """Get url kwargs from request."""
# return self.context.get('request').parser_context.get('kwargs')
#
# def create(self, validated_data):
# menu_pk = self.request_kwargs.get('pk')
# image_id = self.request_kwargs.get('image_id')
# qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk)
# instance = qs.first()
# if instance:
# qs.update(**validated_data)
# return instance
# return super().create(validated_data)
#
# def validate(self, attrs):
# """Override validate method."""
# menu_pk = self.request_kwargs.get('pk')
# image_id = self.request_kwargs.get('image_id')
#
# menu_qs = models.Menu.objects.filter(pk=menu_pk)
# image_qs = Image.objects.filter(id=image_id)
#
# if not menu_qs.exists():
# raise serializers.ValidationError({'detail': _('Menu not found')})
# if not image_qs.exists():
# raise serializers.ValidationError({'detail': _('Image not found')})
#
# menu = menu_qs.first()
# image = image_qs.first()
#
# attrs['menu'] = menu
# attrs['image'] = image
#
# return attrs

View File

@ -9,18 +9,25 @@ 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 location.serializers import AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer, \
CityShortSerializer
from location.serializers import EstablishmentWineRegionBaseSerializer, \
EstablishmentWineOriginBaseSerializer
from establishment.models import Establishment
from location.serializers import (
AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer,
CityShortSerializer,
)
from location.serializers import (
EstablishmentWineRegionBaseSerializer,
EstablishmentWineOriginBaseSerializer,
)
from main.serializers import AwardSerializer, CurrencySerializer
from review.serializers import ReviewShortSerializer
from tag.serializers import TagBaseSerializer
from timetable.serialziers import ScheduleRUDSerializer
from utils import exceptions as utils_exceptions
from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer
from utils.serializers import (ProjectModelSerializer, TranslatedField,
FavoritesCreateSerializer)
from utils.serializers import (
ProjectModelSerializer, TranslatedField,
FavoritesCreateSerializer,
)
logger = logging.getLogger(__name__)
@ -71,19 +78,50 @@ class PlateSerializer(ProjectModelSerializer):
class MenuSerializers(ProjectModelSerializer):
plates = PlateSerializer(read_only=True, many=True, source='plate_set')
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(read_only=True, source='establishment.price_level', required=False)
drinks_included = serializers.BooleanField(source='is_drinks_included', required=FavoritesCreateSerializer)
schedules = ScheduleRUDSerializer(many=True, allow_null=True, required=False)
uploads = serializers.FileField(allow_null=True, required=False)
category_translated = serializers.CharField(read_only=True)
class Meta:
model = models.Menu
fields = [
'id',
'name',
'establishment',
'establishment_id',
'establishment_slug',
'price',
'drinks_included',
'schedules',
'uploads',
'category',
'category_translated',
'plates',
'establishment'
]
def create(self, validated_data):
print(validated_data, '\n\n\n\n\n')
establishment = models.Establishment.objects.get(pk=validated_data.pop('establishment'))
validated_data['establishment'] = establishment['id']
instance = models.Menu.objects.create(**validated_data)
return instance
'''
{
"name": "Menu test",
"establishment_id": 1,
"price": 1,
"drinks_included": true,
"schedules": [],
"uploads": null,
"category": null
}
'''
class MenuRUDSerializers(ProjectModelSerializer):
plates = PlateSerializer(read_only=True, many=True, source='plate_set')

View File

@ -32,9 +32,9 @@ urlpatterns = [
name='establishment-admin-list'),
path('menus/dishes/', views.MenuDishesListCreateView.as_view(), name='menu-dishes-list'),
path('menus/dishes/<int:pk>/', views.MenuDishesRUDView.as_view(), name='menu-dishes-rud'),
path('menus/dishes/<int:pk>/gallery/', views.MenuGalleryListView.as_view(), name='menu-dishes-gallery-list'),
path('menus/dishes/<int:pk>/gallery/<int:image_id>/', views.MenuGalleryCreateDestroyView.as_view(),
name='menu-dishes-gallery-create-destroy'),
# path('menus/dishes/<int:pk>/gallery/', views.MenuGalleryListView.as_view(), name='menu-dishes-gallery-list'),
# path('menus/dishes/<int:pk>/gallery/<int:image_id>/', views.MenuGalleryCreateDestroyView.as_view(),
# name='menu-dishes-gallery-create-destroy'),
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
path('plates/', views.PlateListCreateView.as_view(), name='plates'),

View File

@ -125,6 +125,9 @@ class MenuListCreateView(generics.ListCreateAPIView):
'establishment__slug',
)
def get_queryset(self):
return super().get_queryset().prefetch_related('establishment')
class MenuRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Menu RUD view."""
@ -464,54 +467,54 @@ class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class MenuGalleryListView(generics.ListAPIView):
"""Resource for returning gallery for menu for back-office users."""
serializer_class = serializers.ImageBaseSerializer
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
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 = [IsWineryReviewer | IsEstablishmentManager]
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
# class MenuGalleryListView(generics.ListAPIView):
# """Resource for returning gallery for menu for back-office users."""
# serializer_class = serializers.ImageBaseSerializer
# permission_classes = [IsWineryReviewer | IsEstablishmentManager]
# 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 = [IsWineryReviewer | IsEstablishmentManager]
#
# 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

View File

@ -6,7 +6,7 @@ import string
from collections import namedtuple
from functools import reduce
from io import BytesIO
import pathlib
import requests
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
@ -69,6 +69,15 @@ def username_random():
)
def file_path(instance, filename):
"""Determine file path method."""
filename = '%s.%s' % (generate_code(), pathlib.Path(filename).suffix.lstrip('.'))
return 'files/%s/%s/%s' % (
instance._meta.model_name,
datetime.now().strftime(settings.REST_DATE_FORMAT),
filename)
def image_path(instance, filename):
"""Determine avatar path method."""
filename = '%s.jpeg' % generate_code()

View File

@ -8,6 +8,7 @@ from django.contrib.gis.db import models
from django.contrib.postgres.aggregates import ArrayAgg
from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.fields.jsonb import KeyTextTransform
from django.core.validators import FileExtensionValidator
from django.utils import timezone
from django.utils.html import mark_safe
from django.utils.translation import ugettext_lazy as _, get_language
@ -16,7 +17,7 @@ from sorl.thumbnail import get_thumbnail
from sorl.thumbnail.fields import ImageField as SORLImageField
from configuration.models import TranslationSettings
from utils.methods import image_path, svg_image_path
from utils.methods import image_path, svg_image_path, file_path
from utils.validators import svg_image_validator
logger = logging.getLogger(__name__)
@ -86,6 +87,7 @@ def translate_field(self, field_name, toggle_field_name=None):
return None
return value
return None
return translate
@ -159,6 +161,33 @@ class BaseAttributes(ProjectBaseMixin):
abstract = True
class FileMixin(models.Model):
"""File model."""
file = models.FileField(upload_to=file_path,
blank=True, null=True, default=None,
verbose_name=_('File'),
validators=[FileExtensionValidator(
allowed_extensions=('jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf')
)])
class Meta:
"""Meta class."""
abstract = True
def get_file_url(self):
"""Get file url."""
return self.file.url if self.file else None
def get_full_file_url(self, request):
"""Get full file url"""
if self.file and exists(self.file.path):
return request.build_absolute_uri(self.file.url)
else:
return None
class ImageMixin(models.Model):
"""Avatar model."""
@ -230,7 +259,7 @@ class SORLImageMixin(models.Model):
else:
return None
def get_cropped_image(self, geometry: str, quality: int, cropbox:str) -> dict:
def get_cropped_image(self, geometry: str, quality: int, cropbox: str) -> dict:
cropped_image = get_thumbnail(self.image,
geometry_string=geometry,
# crop=crop,