From c178aea363971f08dc6b204bb63d1007f1cc4537 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Fri, 26 Jun 2020 13:41:41 +0200 Subject: [PATCH] nested serializers and basic recipe editing working --- cookbook/serializer.py | 44 ++----- .../templates/forms/edit_internal_recipe.html | 112 +++++++++++++++++- cookbook/views/api.py | 30 ++++- requirements.txt | 1 + 4 files changed, 149 insertions(+), 38 deletions(-) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index b50469205..862a24d88 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -1,4 +1,5 @@ from django.contrib.auth.models import User +from drf_writable_nested import WritableNestedModelSerializer, UniqueFieldsMixin from rest_framework import serializers from rest_framework.exceptions import APIException from rest_framework.fields import CurrentUserDefault @@ -38,71 +39,50 @@ class SyncLogSerializer(serializers.ModelSerializer): fields = '__all__' -class KeywordSerializer(serializers.ModelSerializer): +class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer): class Meta: model = Keyword fields = '__all__' - validators = [] - extra_kwargs = { - "name": { - "validators": [], - }, - } - - def validate(self, attrs): - return attrs -class UnitSerializer(serializers.ModelSerializer): +class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer): class Meta: model = Unit fields = '__all__' -class FoodSerializer(serializers.ModelSerializer): +class FoodSerializer(UniqueFieldsMixin, serializers.ModelSerializer): class Meta: model = Food fields = '__all__' -class IngredientSerializer(serializers.ModelSerializer): - food = FoodSerializer(read_only=True) - unit = UnitSerializer(read_only=True) +class IngredientSerializer(WritableNestedModelSerializer): + food = FoodSerializer() + unit = UnitSerializer() class Meta: model = Ingredient fields = '__all__' -class StepSerializer(serializers.ModelSerializer): - ingredients = IngredientSerializer(many=True, read_only=True) +class StepSerializer(WritableNestedModelSerializer): + ingredients = IngredientSerializer(many=True) class Meta: model = Step fields = '__all__' -class RecipeSerializer(serializers.ModelSerializer): - steps = StepSerializer(many=True, read_only=True) - keywords = KeywordSerializer(many=True, read_only=False, validators=[]) +class RecipeSerializer(WritableNestedModelSerializer): + steps = StepSerializer(many=True) + keywords = KeywordSerializer(many=True) class Meta: model = Recipe fields = '__all__' validators = [] - def update(self, instance, validated_data): - for k in validated_data['keyword']: - pass - return instance - - def create(self, validated_data): - print('test') - pass - - def validate(self, attrs): - return attrs - class RecipeImportSerializer(serializers.ModelSerializer): class Meta: diff --git a/cookbook/templates/forms/edit_internal_recipe.html b/cookbook/templates/forms/edit_internal_recipe.html index 82c1ecb99..7f0397e9d 100644 --- a/cookbook/templates/forms/edit_internal_recipe.html +++ b/cookbook/templates/forms/edit_internal_recipe.html @@ -61,7 +61,82 @@ - + + + + @@ -81,6 +156,10 @@ recipe: undefined, keywords: [], keywords_loading: false, + foods: [], + foods_loading: false, + units: [], + units_loading: false, }, directives: { tabindex: { @@ -91,6 +170,9 @@ }, mounted: function () { this.loadRecipe() + this.searchUnits('') + this.searchFoods('') + this.searchKeywords('') }, methods: { loadRecipe: function () { @@ -110,15 +192,41 @@ console.log(err) }) }, + addStep: function () { //TODO see if default can be generated from options request + this.recipe.steps.push( + {'instruction': '', ingredients: []} + ) + }, searchKeywords: function (query) { this.keywords_loading = true - this.$http.get("{% url 'api:keyword-list' %}" + '?query=' + query).then((response) => { + this.$http.get("{% url 'api:keyword-list' %}" + '?query=' + query + '&limit=10').then((response) => { this.keywords = response.data; this.keywords_loading = false }).catch((err) => { console.log(err) }) }, + searchUnits: function (query) { + this.units_loading = true + this.$http.get("{% url 'api:unit-list' %}" + '?query=' + query + '&limit=10').then((response) => { + this.units = response.data; + //TODO add back code to include custom created ingredients + this.units_loading = false + }).catch((err) => { + console.log(err) + }) + }, + searchFoods: function (query) { + this.foods_loading = true + this.$http.get("{% url 'api:food-list' %}" + '?query=' + query + '&limit=10').then((response) => { + this.foods = response.data + //TODO add back code to include custom created ingredients + + this.foods_loading = false + }).catch((err) => { + console.log(err) + }) + }, } }); diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 6962dea51..2850ffbad 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -18,7 +18,7 @@ from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, ListMode from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser from cookbook.helper.recipe_url_import import get_from_html -from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference, RecipeBook, Ingredient, Food, Step, Keyword +from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference, RecipeBook, Ingredient, Food, Step, Keyword, Unit from cookbook.provider.dropbox import Dropbox from cookbook.provider.nextcloud import Nextcloud from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \ @@ -112,16 +112,38 @@ class MealTypeViewSet(viewsets.ModelViewSet): class UnitViewSet(viewsets.ModelViewSet): - queryset = Food.objects.all() + queryset = Unit.objects.all() serializer_class = FoodSerializer permission_classes = [CustomIsUser] + def get_queryset(self): # TODO create standard filter/limit mixin + queryset = self.queryset + query = self.request.query_params.get('query', None) + if query is not None: + queryset = queryset.filter(name__icontains=query) + + limit = self.request.query_params.get('limit', None) + if limit is not None: + queryset = queryset[:int(limit)] + return queryset + class FoodViewSet(viewsets.ModelViewSet): queryset = Food.objects.all() serializer_class = FoodSerializer permission_classes = [CustomIsUser] + def get_queryset(self): # TODO create standard filter/limit mixin + queryset = self.queryset + query = self.request.query_params.get('query', None) + if query is not None: + queryset = queryset.filter(name__icontains=query) + + limit = self.request.query_params.get('limit', None) + if limit is not None: + queryset = queryset[:int(limit)] + return queryset + class IngredientViewSet(viewsets.ModelViewSet): queryset = Ingredient.objects.all() @@ -147,7 +169,7 @@ class RecipeViewSet(viewsets.ModelViewSet): serializer_class = RecipeSerializer permission_classes = [permissions.IsAuthenticated] # TODO split read and write permission for meal plan guest - def get_queryset(self): + def get_queryset(self): # TODO create standard filter/limit mixin queryset = Recipe.objects.all() query = self.request.query_params.get('query', None) if query is not None: @@ -171,7 +193,7 @@ class KeywordViewSet(viewsets.ModelViewSet): serializer_class = KeywordSerializer permission_classes = [CustomIsUser] - def get_queryset(self): + def get_queryset(self): # TODO create standard filter/limit mixin queryset = Keyword.objects.all() query = self.request.query_params.get('query', None) if query is not None: diff --git a/requirements.txt b/requirements.txt index 7006b3cb5..156a34765 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ django-emoji-picker==0.0.6 django-filter==2.2.0 django-tables2==2.3.1 djangorestframework==3.11.0 +drf-writable-nested==0.6.0 gunicorn==20.0.4 lxml==4.5.1 Markdown==3.2.2