nested serializers and basic recipe editing working

This commit is contained in:
vabene1111 2020-06-26 13:41:41 +02:00
parent 5e20833b7e
commit c178aea363
4 changed files with 149 additions and 38 deletions

View File

@ -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:

View File

@ -61,7 +61,82 @@
</div>
</div>
<button type="button" @click="updateRecipe()">Save</button>
<template v-for="step, index in recipe.steps">
<div class="row">
<div class="col-md-12">
<h3>Step [[index + 1]]</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<template v-for="ingredient, index in step.ingredients">
<div class="card">
<div class="card-body" style="padding: 12px">
<div class="row">
<div class="col-md-3">
<input class="form-control" v-model="ingredient.amount">
</div>
<div class="col-md-3">
<multiselect v-tabindex
ref="unit"
v-model="ingredient.unit"
:options="units"
:close-on-select="true"
:clear-on-select="true"
:allow-empty="true"
:preserve-search="true"
placeholder="{% trans 'Select one' %}"
tag-placeholder="{% trans 'Select' %}"
label="name"
:id="'unit_' + index"
track-by="id"
:multiple="false"
:loading="units_loading"
@search-change="searchUnits">
</multiselect>
</div>
<div class="col-md-3">
<multiselect v-tabindex
ref="food"
v-model="ingredient.food"
:options="foods"
:close-on-select="true"
:clear-on-select="true"
:allow-empty="true"
:preserve-search="true"
placeholder="{% trans 'Select one' %}"
tag-placeholder="{% trans 'Select' %}"
label="name"
:id="'food_' + index"
track-by="id"
:multiple="false"
:loading="foods_loading"
@search-change="searchFoods">
</multiselect>
</div>
<div class="col-md-3">
<input class="form-control" v-model="ingredient.note">
</div>
</div>
</div>
</div>
</template>
</div>
</div>
<div class="row">
<div class="col-md-12">
<textarea class="form-control" rows="8" v-model="step.instruction"
:id="'id_instruction_' + step.id"></textarea>
</div>
</div>
<br/>
</template>
<button type="button" @click="updateRecipe()" class="btn">Save</button>
<button type="button" @click="addStep()" class="btn">Add Step</button>
</template>
</div>
@ -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)
})
},
}
});
</script>

View File

@ -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:

View File

@ -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