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 review.models import Review
from tag.models import Tag from tag.models import Tag
from utils.methods import transform_into_readable_str from utils.methods import transform_into_readable_str
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, from utils.models import (
TranslatedFieldsMixin, BaseAttributes, GalleryMixin, ProjectBaseMixin, TJSONField, URLImageMixin,
IntermediateGalleryModelMixin, HasTagsMixin, TranslatedFieldsMixin, BaseAttributes, GalleryMixin,
FavoritesMixin, TypeDefaultImageMixin) IntermediateGalleryModelMixin, HasTagsMixin,
FavoritesMixin, TypeDefaultImageMixin, FileMixin,
ImageMixin,
)
# todo: establishment type&subtypes check # todo: establishment type&subtypes check
@ -1272,6 +1275,7 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes):
STR_FIELD_NAME = 'category' STR_FIELD_NAME = 'category'
name = models.CharField(_('name'), max_length=255, default='')
category = TJSONField( category = TJSONField(
blank=True, null=True, default=None, verbose_name=_('category'), blank=True, null=True, default=None, verbose_name=_('category'),
help_text='{"en-GB":"some text"}') help_text='{"en-GB":"some text"}')
@ -1282,9 +1286,14 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes):
schedule = models.ManyToManyField( schedule = models.ManyToManyField(
to='timetable.Timetable', to='timetable.Timetable',
blank=True, blank=True,
verbose_name=_('Establishment schedule'), verbose_name=_('Menu schedule'),
related_name='menus',
) )
uploads = models.ManyToManyField(
to='MenuFiles',
blank=True,
verbose_name=_('Menu files'),
)
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
objects = MenuQuerySet.as_manager() objects = MenuQuerySet.as_manager()
@ -1295,43 +1304,11 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes):
ordering = ('-created',) ordering = ('-created',)
class MenuGallery(IntermediateGalleryModelMixin): class MenuFiles(FileMixin, BaseAttributes):
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):
"""Menu files""" """Menu files"""
menu = models.ForeignKey( name = models.CharField(_('name'), max_length=255, default='')
Menu, type = models.CharField(_('type'), max_length=65, default='')
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')), ],
)
class Meta: class Meta:
verbose_name = _('menu upload') verbose_name = _('menu upload')

View File

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

View File

@ -9,18 +9,25 @@ from rest_framework import serializers
from comment import models as comment_models from comment import models as comment_models
from comment.serializers import common as comment_serializers from comment.serializers import common as comment_serializers
from establishment import models from establishment import models
from location.serializers import AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer, \ from establishment.models import Establishment
CityShortSerializer from location.serializers import (
from location.serializers import EstablishmentWineRegionBaseSerializer, \ AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer,
EstablishmentWineOriginBaseSerializer CityShortSerializer,
)
from location.serializers import (
EstablishmentWineRegionBaseSerializer,
EstablishmentWineOriginBaseSerializer,
)
from main.serializers import AwardSerializer, CurrencySerializer from main.serializers import AwardSerializer, CurrencySerializer
from review.serializers import ReviewShortSerializer from review.serializers import ReviewShortSerializer
from tag.serializers import TagBaseSerializer from tag.serializers import TagBaseSerializer
from timetable.serialziers import ScheduleRUDSerializer from timetable.serialziers import ScheduleRUDSerializer
from utils import exceptions as utils_exceptions from utils import exceptions as utils_exceptions
from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer
from utils.serializers import (ProjectModelSerializer, TranslatedField, from utils.serializers import (
FavoritesCreateSerializer) ProjectModelSerializer, TranslatedField,
FavoritesCreateSerializer,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -71,19 +78,50 @@ class PlateSerializer(ProjectModelSerializer):
class MenuSerializers(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) category_translated = serializers.CharField(read_only=True)
class Meta: class Meta:
model = models.Menu model = models.Menu
fields = [ fields = [
'id', 'id',
'name',
'establishment',
'establishment_id',
'establishment_slug',
'price',
'drinks_included',
'schedules',
'uploads',
'category', 'category',
'category_translated', '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): class MenuRUDSerializers(ProjectModelSerializer):
plates = PlateSerializer(read_only=True, many=True, source='plate_set') plates = PlateSerializer(read_only=True, many=True, source='plate_set')

View File

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

View File

@ -125,6 +125,9 @@ class MenuListCreateView(generics.ListCreateAPIView):
'establishment__slug', 'establishment__slug',
) )
def get_queryset(self):
return super().get_queryset().prefetch_related('establishment')
class MenuRUDView(generics.RetrieveUpdateDestroyAPIView): class MenuRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Menu RUD view.""" """Menu RUD view."""
@ -464,54 +467,54 @@ class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsWineryReviewer | IsEstablishmentManager] permission_classes = [IsWineryReviewer | IsEstablishmentManager]
class MenuGalleryListView(generics.ListAPIView): # class MenuGalleryListView(generics.ListAPIView):
"""Resource for returning gallery for menu for back-office users.""" # """Resource for returning gallery for menu for back-office users."""
serializer_class = serializers.ImageBaseSerializer # serializer_class = serializers.ImageBaseSerializer
permission_classes = [IsWineryReviewer | IsEstablishmentManager] # permission_classes = [IsWineryReviewer | IsEstablishmentManager]
queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() # queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes()
#
def get_object(self): # def get_object(self):
"""Override get_object method.""" # """Override get_object method."""
qs = super(MenuGalleryListView, self).get_queryset() # qs = super(MenuGalleryListView, self).get_queryset()
menu = get_object_or_404(qs, pk=self.kwargs.get('pk')) # menu = get_object_or_404(qs, pk=self.kwargs.get('pk'))
#
# May raise a permission denied # # May raise a permission denied
# self.check_object_permissions(self.request, menu) # # self.check_object_permissions(self.request, menu)
#
return menu # return menu
#
def get_queryset(self): # def get_queryset(self):
"""Override get_queryset method.""" # """Override get_queryset method."""
return self.get_object().crop_gallery # return self.get_object().crop_gallery
#
#
class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin): # class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin):
"""Resource for a create gallery for menu for back-office users.""" # """Resource for a create gallery for menu for back-office users."""
serializer_class = serializers.MenuGallerySerializer # serializer_class = serializers.MenuGallerySerializer
permission_classes = [IsWineryReviewer | IsEstablishmentManager] # permission_classes = [IsWineryReviewer | IsEstablishmentManager]
#
def get_queryset(self): # def get_queryset(self):
"""Override get_queryset method.""" # """Override get_queryset method."""
qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() # qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes()
return qs # return qs
#
def create(self, request, *args, **kwargs): # def create(self, request, *args, **kwargs):
_ = super().create(request, *args, **kwargs) # _ = super().create(request, *args, **kwargs)
news_qs = self.filter_queryset(self.get_queryset()) # news_qs = self.filter_queryset(self.get_queryset())
return response.Response( # return response.Response(
data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data # data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data
) # )
#
def get_object(self): # def get_object(self):
""" # """
Returns the object the view is displaying. # Returns the object the view is displaying.
""" # """
menu_qs = self.filter_queryset(self.get_queryset()) # menu_qs = self.filter_queryset(self.get_queryset())
#
menu = get_object_or_404(menu_qs, pk=self.kwargs.get('pk')) # 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')) # gallery = get_object_or_404(menu.menu_gallery, image_id=self.kwargs.get('image_id'))
#
# May raise a permission denied # # May raise a permission denied
self.check_object_permissions(self.request, gallery) # self.check_object_permissions(self.request, gallery)
#
return gallery # return gallery

View File

@ -6,7 +6,7 @@ import string
from collections import namedtuple from collections import namedtuple
from functools import reduce from functools import reduce
from io import BytesIO from io import BytesIO
import pathlib
import requests import requests
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType 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): def image_path(instance, filename):
"""Determine avatar path method.""" """Determine avatar path method."""
filename = '%s.jpeg' % generate_code() 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.aggregates import ArrayAgg
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.fields.jsonb import KeyTextTransform from django.contrib.postgres.fields.jsonb import KeyTextTransform
from django.core.validators import FileExtensionValidator
from django.utils import timezone from django.utils import timezone
from django.utils.html import mark_safe from django.utils.html import mark_safe
from django.utils.translation import ugettext_lazy as _, get_language 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 sorl.thumbnail.fields import ImageField as SORLImageField
from configuration.models import TranslationSettings 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 from utils.validators import svg_image_validator
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -86,6 +87,7 @@ def translate_field(self, field_name, toggle_field_name=None):
return None return None
return value return value
return None return None
return translate return translate
@ -159,6 +161,33 @@ class BaseAttributes(ProjectBaseMixin):
abstract = True 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): class ImageMixin(models.Model):
"""Avatar model.""" """Avatar model."""
@ -230,7 +259,7 @@ class SORLImageMixin(models.Model):
else: else:
return None 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, cropped_image = get_thumbnail(self.image,
geometry_string=geometry, geometry_string=geometry,
# crop=crop, # crop=crop,