From f4dd21440ff7130854540270c75f534cfd0fe250 Mon Sep 17 00:00:00 2001 From: michigg Date: Sat, 31 Mar 2018 22:58:33 +0200 Subject: [PATCH] Update food api, fix query proplems --- ofu_app/apps/food/admin.py | 3 +- .../food/api/v1_2/serializers/__init__.py | 0 .../main_serializers.py} | 61 ++--------- .../api/v1_2/serializers/user_serializers.py | 100 ++++++++++++++++++ ofu_app/apps/food/api/v1_2/urls.py | 16 ++- ofu_app/apps/food/api/v1_2/views/__init__.py | 0 .../v1_2/{views.py => views/main_views.py} | 39 +++---- .../apps/food/api/v1_2/views/user_views.py | 59 +++++++++++ .../migrations/0013_auto_20180330_1045.py | 24 +++++ .../migrations/0014_singlefood_comments.py | 18 ++++ .../migrations/0015_auto_20180331_1427.py | 23 ++++ .../migrations/0016_auto_20180331_1446.py | 25 +++++ .../food/migrations/0017_foodimage_thumb.py | 18 ++++ .../migrations/0018_remove_foodimage_thumb.py | 17 +++ .../food/migrations/0019_foodimage_thumb.py | 19 ++++ ofu_app/apps/food/models.py | 51 ++++++--- 16 files changed, 380 insertions(+), 93 deletions(-) create mode 100644 ofu_app/apps/food/api/v1_2/serializers/__init__.py rename ofu_app/apps/food/api/v1_2/{serializers.py => serializers/main_serializers.py} (61%) create mode 100644 ofu_app/apps/food/api/v1_2/serializers/user_serializers.py create mode 100644 ofu_app/apps/food/api/v1_2/views/__init__.py rename ofu_app/apps/food/api/v1_2/{views.py => views/main_views.py} (87%) create mode 100644 ofu_app/apps/food/api/v1_2/views/user_views.py create mode 100644 ofu_app/apps/food/migrations/0013_auto_20180330_1045.py create mode 100644 ofu_app/apps/food/migrations/0014_singlefood_comments.py create mode 100644 ofu_app/apps/food/migrations/0015_auto_20180331_1427.py create mode 100644 ofu_app/apps/food/migrations/0016_auto_20180331_1446.py create mode 100644 ofu_app/apps/food/migrations/0017_foodimage_thumb.py create mode 100644 ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py create mode 100644 ofu_app/apps/food/migrations/0019_foodimage_thumb.py diff --git a/ofu_app/apps/food/admin.py b/ofu_app/apps/food/admin.py index 62f0bd6..40c25e2 100644 --- a/ofu_app/apps/food/admin.py +++ b/ofu_app/apps/food/admin.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.contrib import admin -from apps.food.models import SingleFood, Menu, HappyHour, UserFoodRating, UserFoodImage, FoodImage +from apps.food.models import SingleFood, Menu, HappyHour, UserFoodRating, UserFoodImage, FoodImage, UserFoodComment class SingleFoodInline(admin.TabularInline): @@ -24,5 +24,6 @@ admin.site.register(SingleFood) admin.site.register(HappyHour) admin.site.register(UserFoodRating) admin.site.register(UserFoodImage) +admin.site.register(UserFoodComment) admin.site.register(Menu, MenuAdmin) admin.site.register(FoodImage) diff --git a/ofu_app/apps/food/api/v1_2/serializers/__init__.py b/ofu_app/apps/food/api/v1_2/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ofu_app/apps/food/api/v1_2/serializers.py b/ofu_app/apps/food/api/v1_2/serializers/main_serializers.py similarity index 61% rename from ofu_app/apps/food/api/v1_2/serializers.py rename to ofu_app/apps/food/api/v1_2/serializers/main_serializers.py index b5e98dd..f69e118 100644 --- a/ofu_app/apps/food/api/v1_2/serializers.py +++ b/ofu_app/apps/food/api/v1_2/serializers/main_serializers.py @@ -1,11 +1,6 @@ +from apps.food.models import Menu, SingleFood, HappyHour, Allergene, FoodImage, HappyHourLocation, UserFoodComment from rest_framework import serializers -from apps.food.models import Menu, SingleFood, HappyHour, Allergene, FoodImage, HappyHourLocation -from apps.food.models import UserFoodRating, UserFoodImage -from django.contrib.auth.models import User -from rest_framework import serializers -from rest_framework import validators - class DefaultFoodImageSerializer(serializers.Serializer): """Your data serializer, define your fields here.""" @@ -33,6 +28,12 @@ class MenusLocationsSerializer(serializers.Serializer): name = serializers.CharField() +class UserFoodCommentSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = UserFoodComment + fields = ('id', 'description', 'title') + + class AllergensSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Allergene @@ -68,10 +69,12 @@ class MinimalSingleFoodSerializer(serializers.HyperlinkedModelSerializer): class DetailedSingleFoosdSerializer(serializers.HyperlinkedModelSerializer): allergens = AllergensSerializer(many=True, read_only=True) image = DetailedFoodImageSerializer(many=False, read_only=True) + comments = UserFoodCommentSerializer(many=True, read_only=True) class Meta: model = SingleFood - fields = ('id', 'name', 'rating', 'price_student', 'price_employee', 'price_guest', 'allergens', 'image') + fields = ( + 'id', 'name', 'rating', 'price_student', 'price_employee', 'price_guest', 'allergens', 'image', 'comments') class OverviewMenuSerializer(serializers.HyperlinkedModelSerializer): @@ -109,47 +112,3 @@ class HappyHourLocationSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = HappyHourLocation fields = ('id', 'name') - - -# --------------------------- User -------------------------------------------- -class UserFoodImageSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = UserFoodImage - fields = ('id', 'image_image', 'image_thumb') - - -class UserFoodRatingSerializer(serializers.ModelSerializer): - # food = MinimalSingleFoodSerializer(many=False, read_only=False) - - class Meta: - model = UserFoodRating - fields = ('id', 'rating') - - def run_validators(self, value): - for validator in self.validators: - if isinstance(validator, validators.UniqueTogetherValidator): - self.validators.remove(validator) - super(UserFoodRatingSerializer, self).run_validators(value) - - def create(self, validated_data): - # TODO: Custom exception handler - rating = validated_data.pop('rating') - if rating >= 1 or rating <= 5: - food_id = self.context.get('food_id') - # user = self.context['request'].user - user = User.objects.get(id=1) - food = SingleFood.objects.get(id=food_id) - user_rating, _ = UserFoodRating.objects.get_or_create(food=food, user=user) - user_rating.rating = rating - user_rating.save() - - food_user_ratings = UserFoodRating.objects.all().filter(food=food) - sum = 0 - for food_user_rating in food_user_ratings: - sum += food_user_rating.rating - - food.rating = sum / food_user_ratings.count() - food.save() - return user_rating - else: - raise ValueError diff --git a/ofu_app/apps/food/api/v1_2/serializers/user_serializers.py b/ofu_app/apps/food/api/v1_2/serializers/user_serializers.py new file mode 100644 index 0000000..032cf7f --- /dev/null +++ b/ofu_app/apps/food/api/v1_2/serializers/user_serializers.py @@ -0,0 +1,100 @@ +from apps.food.models import Menu, SingleFood +from apps.food.models import UserFoodRating, UserFoodImage, UserFoodComment, FoodImage +from django.contrib.auth.models import User +from rest_framework import validators +from rest_framework import serializers +from django.db.utils import IntegrityError + + +class UserFoodImageSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = UserFoodImage + fields = ('id', 'image_image', 'image_thumb') + + +class UserFoodCommentSerializer(serializers.ModelSerializer): + class Meta: + model = UserFoodComment + fields = ('id', 'title', 'description') + + def run_validators(self, value): + for validator in self.validators: + if isinstance(validator, validators.UniqueTogetherValidator): + self.validators.remove(validator) + super(UserFoodCommentSerializer, self).run_validators(value) + + def create(self, validated_data): + comment_title = validated_data.pop('title') + comment_description = validated_data.pop('description') + food_id = self.context.get('food_id') + user = self.context['request'].user + food = SingleFood.objects.get(id=food_id) + + user_comment, _ = UserFoodComment.objects.get_or_create(food=food, user=user) + user_comment.title = comment_title + user_comment.description = comment_description + user_comment.save() + return user_comment + + +class UserFoodRatingSerializer(serializers.ModelSerializer): + class Meta: + model = UserFoodRating + fields = ('id', 'rating') + + def run_validators(self, value): + for validator in self.validators: + if isinstance(validator, validators.UniqueTogetherValidator): + self.validators.remove(validator) + super(UserFoodRatingSerializer, self).run_validators(value) + + def create(self, validated_data): + # TODO: Custom exception handler + rating = validated_data.pop('rating') + if rating >= 1 or rating <= 5: + food_id = self.context.get('food_id') + user = self.context['request'].user + food = SingleFood.objects.get(id=food_id) + user_rating, _ = UserFoodRating.objects.get_or_create(food=food, user=user) + user_rating.rating = rating + user_rating.save() + + food_user_ratings = UserFoodRating.objects.all().filter(food=food) + sum = 0 + for food_user_rating in food_user_ratings: + sum += food_user_rating.rating + + food.rating = sum / food_user_ratings.count() + food.save() + return user_rating + else: + raise ValueError + + +class UserFoodImageSerializer(serializers.ModelSerializer): + class Meta: + model = FoodImage + fields = ('id', 'image') + + def run_validators(self, value): + for validator in self.validators: + if isinstance(validator, validators.UniqueTogetherValidator): + self.validators.remove(validator) + super(UserFoodImageSerializer, self).run_validators(value) + + def create(self, validated_data): + # TODO: Custom exception handler + food_id = self.context.get('food_id') + food = SingleFood.objects.get(id=food_id) + user = self.context['request'].user + image = validated_data.pop('image') + food_image = FoodImage.objects.create(image=image) + food_image.save() + try: + user_food_image = UserFoodImage.objects.create(user=user, food=food, image=food_image) + user_food_image.save() + except IntegrityError as err: + user_food_image = UserFoodImage.objects.get(user=user, food=food) + user_food_image.image = food_image + user_food_image.save() + return food_image diff --git a/ofu_app/apps/food/api/v1_2/urls.py b/ofu_app/apps/food/api/v1_2/urls.py index 25b8669..89dca3a 100644 --- a/ofu_app/apps/food/api/v1_2/urls.py +++ b/ofu_app/apps/food/api/v1_2/urls.py @@ -14,7 +14,8 @@ Including another URLconf 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.urls import path -from apps.food.api.v1_2 import views as api_views +from apps.food.api.v1_2.views import main_views as api_views +from apps.food.api.v1_2.views import user_views as user_api_views urlpatterns = [ # API Version 1.2 @@ -24,12 +25,17 @@ urlpatterns = [ path('food/meals/', api_views.ApiMeals.as_view(), name='meals'), path('food/meals/', api_views.ApiMeal.as_view(), name='meal'), - path('food/allergens/', api_views.ApiAllergens.as_view(), name='allergens'), + path('food/meals//comments', api_views.ApiMealComments.as_view(), name='meal-comments'), + + path('food/meals//comment', user_api_views.ApiUserFoodCommentUpload.as_view(), name='meals-comment-upload'), + path('food/meals//rating', user_api_views.ApiFoodRatingUpload.as_view(), name='meals-rating-upload'), + path('food/meals//image', user_api_views.ApiFoodImageUpload.as_view(), name='meals-image-upload'), + path('food/meals/image', user_api_views.ApiFoodImageUpload.as_view(), name='meals-image-upload'), + path('food/meals/images/', api_views.ApiFoodImages.as_view(), name='images'), path('food/meals/images/default', api_views.ApiFoodImagesDefault.as_view(), name='images-default'), - path('food/meals//rating', api_views.ApiFoodRatingUpload.as_view(), name='meals-rating-upload'), - # path('food/meals//image', api_views.ApiFoodImagesDefault.as_view(), name='meals-image-upload'), - # path('food/meals//comment', api_views.ApiFoodImagesDefault.as_view(), name='meals-comment-upload'), + + path('food/allergens/', api_views.ApiAllergens.as_view(), name='allergens'), path('food/happy-hours/', api_views.ApiHappyHours.as_view(), name='happy-hours'), path('food/happy-hours/', api_views.ApiHappyHours.as_view(), name='happy-hours'), diff --git a/ofu_app/apps/food/api/v1_2/views/__init__.py b/ofu_app/apps/food/api/v1_2/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ofu_app/apps/food/api/v1_2/views.py b/ofu_app/apps/food/api/v1_2/views/main_views.py similarity index 87% rename from ofu_app/apps/food/api/v1_2/views.py rename to ofu_app/apps/food/api/v1_2/views/main_views.py index b5cbf63..c5cf761 100644 --- a/ofu_app/apps/food/api/v1_2/views.py +++ b/ofu_app/apps/food/api/v1_2/views/main_views.py @@ -6,18 +6,19 @@ from django.templatetags.static import static from datetime import datetime from datetime import timedelta -from apps.food.api.v1_2.serializers import OverviewMenuSerializer, DetailMenuSerializer, MenusLocationsSerializer -from apps.food.api.v1_2.serializers import OverviewSingleFoodSerializer, DetailedSingleFoosdSerializer, \ - AllergensSerializer, DetailedFoodImageSerializer, DefaultFoodImageSerializer, MinimalSingleFoodSerializer -from apps.food.api.v1_2.serializers import HappyHourSerializer, HappyHourLocationSerializer -from apps.food.api.v1_2.serializers import UserFoodRatingSerializer -from apps.food.models import Menu, SingleFood, Allergene, HappyHour, HappyHourLocation, FoodImage, UserFoodRating +from apps.food.api.v1_2.serializers.main_serializers import OverviewMenuSerializer, DetailMenuSerializer, \ + MenusLocationsSerializer +from apps.food.api.v1_2.serializers.main_serializers import OverviewSingleFoodSerializer, DetailedSingleFoosdSerializer, \ + AllergensSerializer, DetailedFoodImageSerializer, DefaultFoodImageSerializer, MinimalSingleFoodSerializer, \ + UserFoodCommentSerializer +from apps.food.api.v1_2.serializers.main_serializers import HappyHourSerializer, HappyHourLocationSerializer +from apps.food.models import Menu, SingleFood, Allergene, HappyHour, HappyHourLocation, FoodImage, UserFoodRating, \ + UserFoodComment from rest_framework import generics from rest_framework.decorators import permission_classes, api_view, authentication_classes from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework import views, status from rest_framework.response import Response -from rest_framework.authentication import TokenAuthentication from rest_framework.exceptions import ValidationError @@ -128,6 +129,15 @@ class ApiMenusLocations(views.APIView): return Response(results, status=status.HTTP_200_OK) +@permission_classes((AllowAny,)) +class ApiMealComments(generics.ListAPIView): + serializer_class = UserFoodCommentSerializer + + def get_queryset(self): + food_id = self.kwargs['pk'] + return UserFoodComment.objects.filter(food_id=food_id) + + @permission_classes((AllowAny,)) class ApiHappyHours(generics.ListAPIView): serializer_class = HappyHourSerializer @@ -209,18 +219,3 @@ class ApiFoodImagesDefault(views.APIView): default_image = {'image': request.build_absolute_uri(static('img/food/default.jpg'))} results = DefaultFoodImageSerializer(default_image, many=False).data return Response(results, status=status.HTTP_200_OK) - - -@authentication_classes((TokenAuthentication,)) -@permission_classes((IsAuthenticated,)) -class ApiFoodRatingUpload(generics.CreateAPIView): - serializer_class = UserFoodRatingSerializer - queryset = UserFoodRating.objects.all() - - def get_serializer_context(self): - context = super(ApiFoodRatingUpload, self).get_serializer_context() - context.update({ - "food_id": self.kwargs['pk'], - # extra data - }) - return context diff --git a/ofu_app/apps/food/api/v1_2/views/user_views.py b/ofu_app/apps/food/api/v1_2/views/user_views.py new file mode 100644 index 0000000..51e9fb4 --- /dev/null +++ b/ofu_app/apps/food/api/v1_2/views/user_views.py @@ -0,0 +1,59 @@ +from rest_framework import generics +from rest_framework.decorators import permission_classes, api_view, authentication_classes +from rest_framework.permissions import IsAuthenticated, AllowAny +from rest_framework.authentication import TokenAuthentication, SessionAuthentication +from rest_framework.parsers import FormParser, MultiPartParser + +from apps.food.models import UserFoodRating, UserFoodImage, UserFoodComment, FoodImage +from apps.food.api.v1_2.serializers.user_serializers import UserFoodRatingSerializer, UserFoodImageSerializer, \ + UserFoodCommentSerializer + + +@authentication_classes((TokenAuthentication, SessionAuthentication)) +@permission_classes((IsAuthenticated,)) +class ApiFoodRatingUpload(generics.CreateAPIView): + serializer_class = UserFoodRatingSerializer + queryset = UserFoodRating.objects.all() + + def get_serializer_context(self): + context = super(ApiFoodRatingUpload, self).get_serializer_context() + context.update({ + "food_id": self.kwargs['pk'], + }) + return context + + +@authentication_classes((TokenAuthentication, SessionAuthentication)) +@permission_classes((IsAuthenticated,)) +class ApiUserFoodCommentUpload(generics.CreateAPIView): + serializer_class = UserFoodCommentSerializer + queryset = UserFoodComment.objects.all() + + def get_serializer_context(self): + context = super(ApiUserFoodCommentUpload, self).get_serializer_context() + context.update({ + "food_id": self.kwargs['pk'], + }) + return context + + +@authentication_classes((TokenAuthentication, SessionAuthentication)) +@permission_classes((IsAuthenticated,)) +class ApiFoodImageUpload(generics.CreateAPIView): + serializer_class = UserFoodImageSerializer + queryset = FoodImage.objects.all() + + def get_serializer_context(self): + context = super(ApiFoodImageUpload, self).get_serializer_context() + context.update({ + "food_id": self.kwargs['pk'], + }) + return context +# +# @authentication_classes((TokenAuthentication,)) +# @permission_classes((IsAuthenticated,)) +# class ApiFoodImageUpload(generics.CreateAPIView): +# serializer_class = UserFoodImageSerializer +# queryset = UserFoodImage.objects.all() +# +# diff --git a/ofu_app/apps/food/migrations/0013_auto_20180330_1045.py b/ofu_app/apps/food/migrations/0013_auto_20180330_1045.py new file mode 100644 index 0000000..7b40158 --- /dev/null +++ b/ofu_app/apps/food/migrations/0013_auto_20180330_1045.py @@ -0,0 +1,24 @@ +# Generated by Django 2.0.1 on 2018-03-30 10:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0012_auto_20180326_2343'), + ] + + operations = [ + migrations.RenameField( + model_name='userfoodcomment', + old_name='comment', + new_name='description', + ), + migrations.AddField( + model_name='userfoodcomment', + name='title', + field=models.CharField(default='Test', max_length=128), + preserve_default=False, + ), + ] diff --git a/ofu_app/apps/food/migrations/0014_singlefood_comments.py b/ofu_app/apps/food/migrations/0014_singlefood_comments.py new file mode 100644 index 0000000..b43e94e --- /dev/null +++ b/ofu_app/apps/food/migrations/0014_singlefood_comments.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-03-30 11:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0013_auto_20180330_1045'), + ] + + operations = [ + migrations.AddField( + model_name='singlefood', + name='comments', + field=models.ManyToManyField(blank=True, to='food.UserFoodComment'), + ), + ] diff --git a/ofu_app/apps/food/migrations/0015_auto_20180331_1427.py b/ofu_app/apps/food/migrations/0015_auto_20180331_1427.py new file mode 100644 index 0000000..11a9c44 --- /dev/null +++ b/ofu_app/apps/food/migrations/0015_auto_20180331_1427.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.1 on 2018-03-31 14:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0014_singlefood_comments'), + ] + + operations = [ + migrations.RemoveField( + model_name='foodimage', + name='thumb', + ), + migrations.AlterField( + model_name='foodimage', + name='image', + field=models.ImageField(default='NULL', upload_to='food/originals/%Y/%m/%W'), + preserve_default=False, + ), + ] diff --git a/ofu_app/apps/food/migrations/0016_auto_20180331_1446.py b/ofu_app/apps/food/migrations/0016_auto_20180331_1446.py new file mode 100644 index 0000000..baaf79c --- /dev/null +++ b/ofu_app/apps/food/migrations/0016_auto_20180331_1446.py @@ -0,0 +1,25 @@ +# Generated by Django 2.0.1 on 2018-03-31 14:46 + +import apps.food.models +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0015_auto_20180331_1427'), + ] + + operations = [ + migrations.AlterField( + model_name='foodimage', + name='image', + field=models.ImageField(upload_to=apps.food.models.image_path), + ), + migrations.AlterField( + model_name='singlefood', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='food.FoodImage'), + ), + ] diff --git a/ofu_app/apps/food/migrations/0017_foodimage_thumb.py b/ofu_app/apps/food/migrations/0017_foodimage_thumb.py new file mode 100644 index 0000000..f126492 --- /dev/null +++ b/ofu_app/apps/food/migrations/0017_foodimage_thumb.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-03-31 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0016_auto_20180331_1446'), + ] + + operations = [ + migrations.AddField( + model_name='foodimage', + name='thumb', + field=models.ImageField(blank=True, null=True, upload_to='food/thumbs/%Y/%m/%W'), + ), + ] diff --git a/ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py b/ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py new file mode 100644 index 0000000..e205cce --- /dev/null +++ b/ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py @@ -0,0 +1,17 @@ +# Generated by Django 2.0.1 on 2018-03-31 15:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0017_foodimage_thumb'), + ] + + operations = [ + migrations.RemoveField( + model_name='foodimage', + name='thumb', + ), + ] diff --git a/ofu_app/apps/food/migrations/0019_foodimage_thumb.py b/ofu_app/apps/food/migrations/0019_foodimage_thumb.py new file mode 100644 index 0000000..d4fd788 --- /dev/null +++ b/ofu_app/apps/food/migrations/0019_foodimage_thumb.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0.1 on 2018-03-31 16:09 + +import apps.food.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0018_remove_foodimage_thumb'), + ] + + operations = [ + migrations.AddField( + model_name='foodimage', + name='thumb', + field=models.ImageField(blank=True, null=True, upload_to=apps.food.models.thumb_path), + ), + ] diff --git a/ofu_app/apps/food/models.py b/ofu_app/apps/food/models.py index 2aa9453..6e74977 100644 --- a/ofu_app/apps/food/models.py +++ b/ofu_app/apps/food/models.py @@ -3,6 +3,8 @@ from __future__ import unicode_literals import os from io import BytesIO +import uuid +from _datetime import datetime from PIL import Image from django.conf import settings @@ -19,9 +21,22 @@ MAX_FOOD_PRICE_LENGTH = 10 MAX_FOOD_ALLERGENNAME_LENGTH = 256 MAX_HAPPY_HOUR_LOCATION_LENGTH = 256 MAX_HAPPY_HOUR_DESCRIPTION_LENGTH = 1024 +MAX_FOOD_COMMENT_TITLE_LENGTH = 128 MAX_FOOD_COMMENT_LENGTH = 2048 +def image_path(instance, filename): + extension = filename.split('.')[-1] + date = datetime.now().strftime('%Y/%m/%W') + return 'food/originals/{}/{}.{}'.format(date, uuid.uuid4(), extension) + + +def thumb_path(instance, filename): + extension = filename.split('.')[-1] + date = datetime.now().strftime('%Y/%m/%W') + return 'food/thumbs/{}/{}.{}'.format(date, uuid.uuid4(), 'jpg') + + # Create your models here. class Menu(models.Model): ERBA = 'ERBA' @@ -56,9 +71,10 @@ class SingleFood(models.Model): price_student = models.CharField(max_length=MAX_FOOD_PRICE_LENGTH, blank=True, null=True) price_employee = models.CharField(max_length=MAX_FOOD_PRICE_LENGTH, blank=True, null=True) price_guest = models.CharField(max_length=MAX_FOOD_PRICE_LENGTH, blank=True, null=True) - image = models.ForeignKey('FoodImage', on_delete=models.PROTECT, blank=True, null=True) + image = models.ForeignKey('FoodImage', on_delete=models.SET_NULL, blank=True, null=True) rating = models.FloatField(default=0) allergens = models.ManyToManyField("Allergene", blank=True) + comments = models.ManyToManyField('UserFoodComment', blank=True) def __str__(self): return "%s - Rating: %f - Student Price: %s" % (self.name, self.rating, self.price_student) @@ -125,25 +141,27 @@ class UserFoodComment(models.Model): id = models.AutoField(primary_key=True) user = models.ForeignKey(User, on_delete=models.PROTECT, unique=False) food = models.ForeignKey(SingleFood, on_delete=models.PROTECT) - comment = models.CharField(max_length=MAX_FOOD_COMMENT_LENGTH) + title = models.CharField(max_length=MAX_FOOD_COMMENT_TITLE_LENGTH, null=False, blank=False) + description = models.CharField(max_length=MAX_FOOD_COMMENT_LENGTH, null=False, blank=False) class Meta: unique_together = ('user', 'food') def __str__(self): - return "User: %s - Food: %s" % (self.user.username, self.food.name) + return "User: %s - Title: %s" % (self.user.username, self.title) class FoodImage(models.Model): id = models.AutoField(primary_key=True) - image = models.ImageField(upload_to='food/originals/%Y/%m/%W', blank=True, null=True) - thumb = models.ImageField(upload_to='food/thumbs/%Y/%m/%W', blank=True, null=True) + image = models.ImageField(upload_to=image_path, blank=False, null=False) + thumb = models.ImageField(upload_to=thumb_path, blank=True, null=True) - def save(self, force_update=False, force_insert=False, thumb_size=(640, 480)): + def save(self, *args, **kwargs): image = Image.open(self.image) if image.mode not in ('L', 'RGB'): image = image.convert('RGB') + thumb_size = (128, 128) image.thumbnail(thumb_size, Image.ANTIALIAS) # save the thumbnail to memory @@ -156,12 +174,17 @@ class FoodImage(models.Model): temp_handle.read(), content_type='image/jpg') - self.thumb.save('%s_thumbnail.%s' % (self.id, 'jpg'), suf, save=False) - # save the image object - self.image.name = "%s_original.%s" % (self.id, 'jpg') - super(FoodImage, self).save(force_update, force_insert) + # self.thumb.save('%s_thumbnail.%s' % (self.id, 'jpg'), suf, save=False) + self.thumb.save(name='', content=suf, save=False) - def delete(self, using=None, keep_parents=False): - os.remove(os.path.join(settings.MEDIA_ROOT, self.image.name)) - os.remove(os.path.join(settings.MEDIA_ROOT, self.thumb.name)) - super(FoodImage, self).delete() + # save the image object + super(FoodImage, self).save(*args, **kwargs) + + # + # def delete(self, using=None, keep_parents=False): + # os.remove(os.path.join(settings.MEDIA_ROOT, self.image.name)) + # os.remove(os.path.join(settings.MEDIA_ROOT, self.thumb.name)) + # super(FoodImage, self).delete() + + def __str__(self): + return "Image: %s" % (str(self.image))