Start api v1.2

This commit is contained in:
michigg 2018-03-28 15:18:54 +02:00
parent e2e2e0b0bf
commit 4fd22aed1d
7 changed files with 326 additions and 181 deletions

View File

View File

@ -14,7 +14,7 @@ Including another URLconf
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from apps.food.api import views as api_views
from apps.food.api.v1_1 import views as api_views
from apps.food.models import Menu
urlpatterns = [

View File

@ -4,11 +4,11 @@ from __future__ import unicode_literals
from datetime import datetime
from datetime import timedelta
from apps.food.api.serializers import MenuSerializer, HappyHourSerializer
from apps.food.api.v1_1.serializers import MenuSerializer, HappyHourSerializer
from apps.food.models import Menu, HappyHour
from rest_framework import viewsets
from rest_framework.decorators import api_view, permission_classes
from rest_framework.decorators import permission_classes
from rest_framework.permissions import AllowAny

View File

View File

@ -1,18 +1,36 @@
from rest_framework import serializers
from apps.food.models import Menu, SingleFood, HappyHour, Allergene, UserFoodImage, FoodImage
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 UserFoodImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserFoodImage
fields = ('id', 'image_image', 'image_thumb')
class DefaultFoodImageSerializer(serializers.Serializer):
"""Your data serializer, define your fields here."""
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
image = serializers.CharField()
class FoodImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = FoodImage
fields = ('id', 'image', 'thumb')
class MenusLocationsSerializer(serializers.Serializer):
"""Your data serializer, define your fields here."""
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
id = serializers.CharField()
short = serializers.CharField()
name = serializers.CharField()
class AllergensSerializer(serializers.HyperlinkedModelSerializer):
@ -21,18 +39,44 @@ class AllergensSerializer(serializers.HyperlinkedModelSerializer):
fields = ('id', 'name')
class SingleFoodSerializer(serializers.HyperlinkedModelSerializer):
allergens = AllergensSerializer(many=True, read_only=True)
image = FoodImageSerializer(many=False, read_only=True)
class OverviewFoodImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = FoodImage
fields = ('id', 'thumb')
class DetailedFoodImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = FoodImage
fields = ('id', 'image', 'thumb')
class OverviewSingleFoodSerializer(serializers.HyperlinkedModelSerializer):
image = OverviewFoodImageSerializer(many=False, read_only=True)
class Meta:
model = SingleFood
fields = ('name', 'rating', 'price_student', 'price_employee', 'price_guest', 'allergens', 'image')
fields = ('id', 'name', 'rating', 'price_student', 'image')
class MenuSerializer(serializers.HyperlinkedModelSerializer):
class MinimalSingleFoodSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = SingleFood
fields = ('id', 'name')
class DetailedSingleFoosdSerializer(serializers.HyperlinkedModelSerializer):
allergens = AllergensSerializer(many=True, read_only=True)
image = DetailedFoodImageSerializer(many=False, read_only=True)
class Meta:
model = SingleFood
fields = ('id', 'name', 'rating', 'price_student', 'price_employee', 'price_guest', 'allergens', 'image')
class OverviewMenuSerializer(serializers.HyperlinkedModelSerializer):
date = serializers.DateField(format='iso-8601')
menu = SingleFoodSerializer(many=True, read_only=True)
menu = OverviewSingleFoodSerializer(many=True, read_only=True)
location = serializers.ChoiceField(choices=Menu.LOCATION_CHOICES)
class Meta:
@ -40,6 +84,17 @@ class MenuSerializer(serializers.HyperlinkedModelSerializer):
fields = ('id', 'date', 'location', 'menu')
class DetailMenuSerializer(serializers.HyperlinkedModelSerializer):
date = serializers.DateField(format='iso-8601')
menu = DetailedSingleFoosdSerializer(many=True, read_only=True)
location = serializers.ChoiceField(choices=Menu.LOCATION_CHOICES)
class Meta:
model = Menu
fields = ('id', 'date', 'location', 'menu')
# -------------------------- Happy Hour ------------------------------------
class HappyHourSerializer(serializers.HyperlinkedModelSerializer):
date = serializers.DateField(format='iso-8601')
starttime = serializers.TimeField()
@ -48,3 +103,53 @@ class HappyHourSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = HappyHour
fields = ('id', 'date', 'starttime', 'endtime', 'location', 'description')
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

View File

@ -13,21 +13,25 @@ Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from apps.food.api.v1_1 import views as api_views
from apps.food.models import Menu
from django.urls import path
from apps.food.api.v1_2 import views as api_views
urlpatterns = [
# API Version 1.1
url(r'^food/$', api_views.FoodViewSetV1_1.as_view({'get': 'list'}), name='api-v1_1-food-all'),
url(r'^food/(?P<location>' + Menu.FEKI + '|' + Menu.MARKUSPLATZ + '|' + Menu.ERBA + '|' + Menu.AUSTRASSE + ')/$',
api_views.FoodViewSetV1_1.as_view({'get': 'list'}), name='api-v1_1-food-location'),
url(r'food/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$',
api_views.FoodViewSetV1_1.as_view({'get': 'list'}), name='api-v1_1-food-date'),
url(
r'food/(?P<location>' + Menu.FEKI + '|' + Menu.MARKUSPLATZ + '|' + Menu.ERBA + '|' + Menu.AUSTRASSE + ')/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$',
api_views.FoodViewSetV1_1.as_view({'get': 'list'}), name='api-v1_1-food-location-date'),
url(r'food/today/$', api_views.FoodViewSetV1_1.as_view({'get': 'list'}), name='api-v1_1-food-today'),
url(r'food/week/$', api_views.FoodViewSetV1_1.as_view({'get': 'list'}), name='api-v1_1-food-week'),
url(r'happy-hour', api_views.HappyHourViewSet.as_view({'get': 'list'}), name='api-v1_1-happy-hour-all'),
# API Version 1.2
path('food/menus/', api_views.ApiMenus.as_view(), name='menus'),
path('food/menus/<int:pk>/', api_views.ApiMenu.as_view(), name='menu'),
path('food/menus/locations', api_views.ApiMenusLocations.as_view(), name='menus-locations'),
path('food/meals/', api_views.ApiMeals.as_view(), name='meals'),
path('food/meals/<int:pk>', api_views.ApiMeal.as_view(), name='meal'),
path('food/allergens/', api_views.ApiAllergens.as_view(), name='allergens'),
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/<int:pk>/rating', api_views.ApiFoodRatingUpload.as_view(), name='meals-rating-upload'),
# path('food/meals/<int:pk>/image', api_views.ApiFoodImagesDefault.as_view(), name='meals-image-upload'),
# path('food/meals/<int:pk>/comment', api_views.ApiFoodImagesDefault.as_view(), name='meals-comment-upload'),
path('food/happy-hours/', api_views.ApiHappyHours.as_view(), name='happy-hours'),
path('food/happy-hours/<int:pk>', api_views.ApiHappyHours.as_view(), name='happy-hours'),
path('food/happy-hours/locations', api_views.ApiHappyHoursLocations.as_view(), name='happy-hours-locations'),
]

View File

@ -1,190 +1,226 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.templatetags.static import static
from datetime import datetime
from datetime import timedelta
from apps.food.api.v1_1.serializers import MenuSerializer, HappyHourSerializer
from apps.food.models import Menu, HappyHour
from rest_framework import viewsets
from rest_framework.decorators import permission_classes
from rest_framework.permissions import AllowAny
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 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
# @api_view(['GET'])
@permission_classes((AllowAny,))
class FoodViewSet(viewsets.ModelViewSet, ):
"""
API endpoint that allows users to be viewed or edited.
"""
# queryset = Menu.objects.all()
serializer_class = MenuSerializer
class ApiMenus(generics.ListAPIView):
serializer_class = OverviewMenuSerializer
def get_queryset(self):
queryset = Menu.objects.all()
location = self.request.query_params.get('location')
date = self.request.query_params.get('date')
print(str(location).upper() == Menu.ERBA.upper())
start_date = self.request.query_params.get('startdate')
end_date = self.request.query_params.get('enddate')
if location:
print(str(location).upper() == Menu.ERBA.upper())
if str(location).upper() is Menu.ERBA.upper():
queryset = queryset.filter(location_contains='Erba')
elif str(location).upper() is Menu.FEKI.upper():
queryset = queryset.filter(location=Menu.FEKI)
elif str(location).upper() is Menu.AUSTRASSE.upper():
queryset = queryset.filter(location=Menu.AUSTRASSE)
elif str(location).upper() is Menu.MARKUSPLATZ.upper():
queryset = queryset.filter(location=Menu.MARKUSPLATZ)
if date:
if date == "week":
today = datetime.now()
weekday = today.weekday()
monday = today - timedelta(weekday)
sunday = today + (timedelta(6 - weekday))
print("Monday: " + str(monday))
print("Sunday: " + str(sunday))
queryset = queryset.filter(date__gte=monday, date__lte=sunday)
if str(location).upper() == Menu.ERBA.upper():
queryset = queryset.filter(location__contains=Menu.ERBA)
elif str(location).upper() == Menu.FEKI.upper():
queryset = queryset.filter(location__contains=Menu.FEKI)
elif str(location).upper() == Menu.AUSTRASSE.upper():
queryset = queryset.filter(location__contains=Menu.AUSTRASSE)
elif str(location).upper() == Menu.MARKUSPLATZ.upper():
queryset = queryset.filter(location__contains=Menu.MARKUSPLATZ)
else:
queryset = queryset.filter(date=datetime.strptime(date, "%Y-%m-%d"))
queryset = []
if start_date:
try:
queryset = queryset.filter(date__gte=datetime.strptime(start_date, '%Y-%m-%d'))
except ValueError as e:
# TODO: return Exception
return []
print("LOCATION: %s" % str(location))
print("DATE: " + str(date))
print(str(queryset))
if end_date:
try:
queryset = queryset.filter(date__lte=datetime.strptime(end_date, '%Y-%m-%d'))
except ValueError as e:
# TODO: return Exception
return []
return queryset
# @api_view(['GET'])
@permission_classes((AllowAny,))
class FoodViewSetV1_1(viewsets.ModelViewSet, ):
"""
API endpoint that allows users to be viewed or edited.
"""
# queryset = Menu.objects.all()
serializer_class = MenuSerializer
class ApiMenu(generics.RetrieveAPIView):
serializer_class = DetailMenuSerializer
queryset = Menu.objects.all()
@permission_classes((AllowAny,))
class ApiMeals(generics.ListAPIView):
serializer_class = OverviewSingleFoodSerializer
def get_queryset(self):
queryset = Menu.objects.all()
location = None
if 'location' in self.kwargs:
location = self.kwargs['location']
queryset = SingleFood.objects.all()
rating = self.request.query_params.get('rating')
max_rating = self.request.query_params.get('max-rating')
min_rating = self.request.query_params.get('min-rating')
year = None
if 'year' in self.kwargs:
year = self.kwargs['year']
month = None
if 'month' in self.kwargs:
month = self.kwargs['month']
day = None
if 'day' in self.kwargs:
day = self.kwargs['day']
price = self.request.query_params.get('price')
max_price = self.request.query_params.get('max-price')
min_price = self.request.query_params.get('min-price')
if location:
if str(location).upper() == Menu.ERBA.upper():
queryset = queryset.filter(location__contains=Menu.ERBA)
elif str(location).upper() == Menu.FEKI.upper():
queryset = queryset.filter(location__contains=Menu.FEKI)
elif str(location).upper() == Menu.AUSTRASSE.upper():
print("Before: " + str(queryset))
queryset = queryset.filter(location__contains=Menu.AUSTRASSE)
elif str(location).upper() == Menu.MARKUSPLATZ.upper():
queryset = queryset.filter(location__contains=Menu.MARKUSPLATZ)
print(queryset)
if year and month and day:
date = '%s-%s-%s' % (year, month, day)
queryset = queryset.filter(date=datetime.strptime(date, '%Y-%m-%d'))
allergens = self.request.query_params.get('allergens')
# if date == "week":
# today = datetime.now()
# weekday = today.weekday()
# monday = today - timedelta(weekday)
# sunday = today + (timedelta(6 - weekday))
# print("Monday: " + str(monday))
# print("Sunday: " + str(sunday))
# queryset = queryset.filter(date__gte=monday, date__lte=sunday)
# else:
# queryset = queryset.filter(date=datetime.strptime(date, "%Y-%m-%d"))
if rating:
queryset = queryset.filter(rating=rating)
print("LOCATION: %s" % str(location))
print(str(queryset))
if max_rating:
queryset = queryset.filter(rating__lte=max_rating)
if min_rating:
queryset = queryset.filter(rating__gte=min_rating)
# TODO: Change price model to Floatfield
# if price:
# pass
#
# if max_price:
# pass
#
# if min_price:
# pass
if allergens:
allergens = [allergen for allergen in str(allergens).strip('[]').split(',')]
queryset = queryset.filter(allergens__id__in=allergens)
return queryset
# @api_view(['GET'])
@permission_classes((AllowAny,))
class FoodViewSetV1_1(viewsets.ModelViewSet, ):
"""
API endpoint that allows users to be viewed or edited.
"""
# queryset = Menu.objects.all()
serializer_class = MenuSerializer
def get_queryset(self):
queryset = Menu.objects.all()
location = None
if 'location' in self.kwargs:
location = self.kwargs['location']
year = None
if 'year' in self.kwargs:
year = self.kwargs['year']
month = None
if 'month' in self.kwargs:
month = self.kwargs['month']
day = None
if 'day' in self.kwargs:
day = self.kwargs['day']
if location:
if str(location).upper() == Menu.ERBA.upper():
queryset = queryset.filter(location__contains=Menu.ERBA)
elif str(location).upper() == Menu.FEKI.upper():
queryset = queryset.filter(location__contains=Menu.FEKI)
elif str(location).upper() == Menu.AUSTRASSE.upper():
print("Before: " + str(queryset))
queryset = queryset.filter(location__contains=Menu.AUSTRASSE)
elif str(location).upper() == Menu.MARKUSPLATZ.upper():
queryset = queryset.filter(location__contains=Menu.MARKUSPLATZ)
print(queryset)
if year and month and day:
date = '%s-%s-%s' % (year, month, day)
queryset = queryset.filter(date=datetime.strptime(date, '%Y-%m-%d'))
# if date == "week":
# today = datetime.now()
# weekday = today.weekday()
# monday = today - timedelta(weekday)
# sunday = today + (timedelta(6 - weekday))
# print("Monday: " + str(monday))
# print("Sunday: " + str(sunday))
# queryset = queryset.filter(date__gte=monday, date__lte=sunday)
# else:
# queryset = queryset.filter(date=datetime.strptime(date, "%Y-%m-%d"))
print("LOCATION: %s" % str(location))
print(str(queryset))
return queryset
class ApiMeal(generics.RetrieveAPIView):
serializer_class = DetailedSingleFoosdSerializer
queryset = SingleFood.objects.all()
# @api_view(['GET'])
@permission_classes((AllowAny,))
class HappyHourViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = HappyHour.objects.all()
class ApiAllergens(generics.ListAPIView):
serializer_class = AllergensSerializer
queryset = Allergene.objects.all()
@permission_classes((AllowAny,))
class ApiMenusLocations(views.APIView):
def get(self, request):
locations = Menu.API_LOCATIONS
results = MenusLocationsSerializer(locations, many=True).data
return Response(results, status=status.HTTP_200_OK)
@permission_classes((AllowAny,))
class ApiHappyHours(generics.ListAPIView):
serializer_class = HappyHourSerializer
def get_queryset(self):
queryset = HappyHour.objects.all()
type = self.request.query_params.get('type')
date = self.request.query_params.get('date')
start_date = self.request.query_params.get('startdate')
end_date = self.request.query_params.get('enddate')
# if type == "food":
# queryset = HappyHour.filter(location__contains="Austraße")
# elif type == "drinks":
# queryset = HappyHour.filter(location__contains="Austraße")
start_time = self.request.query_params.get('starttime')
end_time = self.request.query_params.get('endtime')
location = self.request.query_params.get('location')
if date:
try:
queryset = queryset.filter(date=datetime.strptime(date, '%Y-%m-%d'))
except ValueError as e:
# TODO: return Exception
return []
if start_date:
try:
queryset = queryset.filter(date__gte=datetime.strptime(start_date, '%Y-%m-%d'))
except ValueError as e:
# TODO: return Exception
return []
if end_date:
try:
queryset = queryset.filter(date__lte=datetime.strptime(start_date, '%Y-%m-%d'))
except ValueError as e:
# TODO: return Exception
return []
if start_time:
try:
queryset = queryset.filter(date__lte=datetime.strptime(start_time, '%H'))
except ValueError as e:
# TODO: return Exception
return []
if end_time:
try:
queryset = queryset.filter(date__lte=datetime.strptime(end_time, '%H'))
except ValueError as e:
# TODO: return Exception
return []
if location:
queryset = queryset.filter(location__id=location)
return queryset
@permission_classes((AllowAny,))
class ApiHappyHoursLocations(generics.RetrieveAPIView):
serializer_class = HappyHourSerializer
queryset = HappyHour.objects.all()
@permission_classes((AllowAny,))
class ApiHappyHoursLocations(generics.ListAPIView):
serializer_class = HappyHourLocationSerializer
queryset = HappyHourLocation.objects.all()
@permission_classes((AllowAny,))
class ApiFoodImages(generics.ListAPIView):
serializer_class = DetailedFoodImageSerializer
queryset = FoodImage.objects.all()
@permission_classes((AllowAny,))
class ApiFoodImagesDefault(views.APIView):
def get(self, request):
request.build_absolute_uri(static('img/food/default.jpg'))
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