#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sun Apr 24 14:32:15 2022 @author: elena """ from django.db.utils import IntegrityError from rest_framework import serializers from .models import * class MarketSerializer(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') class Meta: model = Market fields = ('id','name', 'street', 'street_number', 'zip_code', 'city', 'phone','articles','created','modified') def pk(self, obj): return obj.pk class ReceipeImageSerializer(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') class Meta: model = Market fields = ('id','pk') def pk(self, obj): return obj.pk class PurchaseSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) purchase_date = serializers.DateField() payment_type = serializers.CharField(max_length=20) total_price = serializers.DecimalField(max_digits=7,decimal_places=2) market = MarketSerializer() edit_finished = serializers.BooleanField() receipeImage = ReceipeImageSerializer() def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Purchase` instance, given the validated data. """ try: return Purchase.objects.create(**validated_data) except IntegrityError: return Purchase.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Purchase` instance, given the validated data. """ instance.purchase_date = validated_data.get('purchase_date', instance.purchase_date) instance.save() return instance ''' class PurchaseSerializer(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') class Meta: model = Purchase fields = ('id','purchase_date', 'payment_type', 'total_price', 'articles', 'market', 'created','modified','receipeImage','edit_finished') depth = 0 def pk(self, obj): return obj.pk ''' class PurchaseSerializerDepth(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') class Meta: model = Purchase fields = ('id','purchase_date', 'payment_type', 'total_price', 'articles', 'market', 'created','modified','receipeImage','edit_finished') depth = 1 def pk(self, obj): return obj.pk class NutritionalValuesSerializer(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') class Meta: model = NutritionalValues fields = '__all__' def pk(self, obj): return obj.pk class ReceipeStringSerializer(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') class Meta: model = ReceipeString fields = '__all__' def pk(self, obj): return obj.pk class ArticleMapSerzializer(serializers.ModelSerializer): class Meta: model = ArticleMaps fields = ('pk','receipeString','location_x','location_y','location_h','location_w') depth = 1 class CategorySerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=30) path = serializers.CharField(max_length=255) depth = serializers.IntegerField() numchild = serializers.IntegerField() ancestorIds = serializers.SerializerMethodField() def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Category` instance, given the validated data. """ try: return Category.objects.create(**validated_data) except IntegrityError: return Category.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Category` instance, given the validated data. """ instance.name = validated_data.get('name', instance.name) instance.save() return instance # For visualisation we need the ids of all ancestors, in order to expand the tree. Therefore we fetch the data here def get_ancestorIds(self, obj): ancestors = obj.get_ancestors() ids = [] for element in ancestors: ids.append(element.id) return ids class AllergenesSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Allergenes` instance, given the validated data. """ try: return Allergenes.objects.create(**validated_data) except IntegrityError: return Allergenes.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Allergenes` instance, given the validated data. """ instance.name = validated_data.get('name', instance.name) instance.save() return instance class TracesSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Traces` instance, given the validated data. """ try: return Traces.objects.create(**validated_data) except IntegrityError: return Traces.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Traces` instance, given the validated data. """ instance.name = validated_data.get('name', instance.name) instance.save() return instance class RecursiveField(serializers.Serializer): def to_representation(self, value): serializer = self.parent.parent.__class__(value, context=self.context) return serializer.data class IngredientsSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=100) allergenes = AllergenesSerializer(allow_null = True, many=True) vegan = serializers.BooleanField(allow_null = True) vegetarian = serializers.BooleanField(allow_null = True) palmoilfree = serializers.BooleanField(allow_null = True) additive = serializers.BooleanField(allow_null = True) eNumber = serializers.CharField(max_length=7, allow_null = True, allow_blank=True) subIngredients = RecursiveField(allow_null= True, many=True)#IngredientsSerializer(allow_null = True, many=True) #serializers.ListField() def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Ingredients` instance, given the validated data. """ print("Ingredients:Create") #print(validated_data) allergenes = validated_data.pop('allergenes') subIngredients = validated_data.pop('subIngredients') print(subIngredients) allergenes_list = [] subIngredients_list = [] for allergene in allergenes: allergenes_list.append(Allergenes.objects.get(name=allergene['name'])) for subIngredient in subIngredients: print(subIngredient) subIngredients_list.append(Ingredients.objects.get(name=subIngredient['name'])) print(allergenes_list) try: newObject = Ingredients.objects.create(**validated_data) newObject.allergenes.set(allergenes_list) newObject.subIngredients.set(subIngredients_list) newObject.save() print(newObject) return newObject except IntegrityError: return Ingredients.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Ingredients` instance, given the validated data. """ instance.name = validated_data.get('name', instance.name) instance.save() return instance # Validate if subIngredients are given, if not raise error. This is needed, because value is emtpy, therefore we have to access the inital data def validate_subIngredients(self, value): print("Ingredients:Validate subIngredients") print(value) print(self.context) #print(self.initial_data) #print(self.initial_data['subIngredients']) if not 'subIngredients' in self.context: self.context['subIngredients'] = [] return self.context['subIngredients'] else: return self.context['subIngredients'] #IngredientsSerializer.base_fields['subIngredients'] = IngredientsSerializer(allow_null = True, many=True) class LabelsSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Brand` instance, given the validated data. """ print("Labels:Create") try: return Labels.objects.create(**validated_data) except IntegrityError: return Labels.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Snippet` instance, given the validated data. """ print("Labels:Update") instance.name = validated_data.get('name', instance.name) instance.save() return instance class PackagingSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Packaging` instance, given the validated data. """ print("Packaging:Create") try: return Packaging.objects.create(**validated_data) except IntegrityError: return Packaging.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Packaging` instance, given the validated data. """ print("Labels:Update") instance.name = validated_data.get('name', instance.name) instance.save() return instance class EMBSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `EMBs` instance, given the validated data. """ print("Brand:Create") try: return EMBs.objects.create(**validated_data) except IntegrityError: return EMBs.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `EMBs` instance, given the validated data. """ print("Brand:Update") instance.name = validated_data.get('name', instance.name) instance.save() return instance class ManufacturingPlacesSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Brand` instance, given the validated data. """ print("Brand:Create") try: return ManufacturingPlaces.objects.create(**validated_data) except IntegrityError: return ManufacturingPlaces.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Snippet` instance, given the validated data. """ print("Brand:Update") instance.name = validated_data.get('name', instance.name) instance.save() return instance class OriginIngredientsSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Brand` instance, given the validated data. """ try: return OriginIngredients.objects.create(**validated_data) except IntegrityError: return OriginIngredients.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Snippet` instance, given the validated data. """ instance.name = validated_data.get('name', instance.name) instance.save() return instance class BrandSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Brand` instance, given the validated data. """ print("Brand:Create") try: return Brand.objects.create(**validated_data) except IntegrityError: return Brand.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Snippet` instance, given the validated data. """ print("Brand:Update") instance.name = validated_data.get('name', instance.name) instance.save() return instance #def validate_name(self, value): # print('Validate: name') # return value #def validate(self, data): # print('Validate object: name') # return data class ArticleSerializer(serializers.ModelSerializer): brand = BrandSerializer(allow_null = True) allergenes = AllergenesSerializer(allow_null = True, many=True) #ingredients = IngredientsSerializer(allow_null = True, many=True) traces = TracesSerializer(allow_null = True, many=True) labels = LabelsSerializer(allow_null = True, many=True) #packagings = PackagingArticleSerializer(allow_null = True, many=True) embs = EMBSerializer(allow_null = True, many=True) manufacturingPlaces = ManufacturingPlacesSerializer(allow_null = True, many=True) originIngredients = OriginIngredientsSerializer(allow_null = True, many=True) nutritionImage = serializers.ImageField(read_only = True) ingredientsImage = serializers.ImageField(read_only = True) frontImage = serializers.ImageField(read_only = True) category = CategorySerializer(allow_null = True) class Meta: model = Article fields = ('pk','name','brand','EAN','offlink','category', 'quantityPerPackage','unit','novaGroup','nutritionGrade','ecoGrade', 'MwSt','allergenes','traces','embs','labels', 'manufacturingPlaces','originIngredients', 'created','modified', 'nutritionImage','ingredientsImage', 'frontImage') # 'ingredients', depth = 1 def update(self, instance, validated_data): print("update method") print(validated_data) article = self.fill_deeper_fields(instance, validated_data) article.name = validated_data.pop('name') article.EAN = validated_data.pop('EAN') article.offlink = validated_data.pop('offlink') article.quantityPerPackage = validated_data.pop('quantityPerPackage') article.unit = validated_data.pop('unit') article.novaGroup = validated_data.pop('novaGroup') article.nutritionGrade = validated_data.pop('nutritionGrade') article.ecoGrade = validated_data.pop('ecoGrade') article.MwSt = validated_data.pop('MwSt') #print("Article before save") #print(article.labels.get()) article.save() return article def create(self, validated_data): print('create method') article = Article.objects.create(**validated_data) article = self.fill_deeper_fields(article, validated_data) article.name = validated_data.pop('name') article.EAN = validated_data.pop('EAN') article.quantityPerPackage = validated_data.pop('quantityPerPackage') article.unit = validated_data.pop('unit') article.novaGroup = validated_data.pop('novaGroup') article.nutritionGrade = validated_data.pop('nutritionGrade') article.ecoGrade = validated_data.pop('ecoGrade') article.MwSt = validated_data.pop('MwSt') return article def deserialize_multi_field(self, data_list, model): elements = [] for data in data_list: if data != None: #if model == 'ingredients': # serializer = IngredientsSerializer( # data=data # ) if model == 'allergenes': serializer = AllergenesSerializer( data=data ) elif model == 'traces': serializer = TracesSerializer( data=data ) elif model == 'labels': serializer = LabelsSerializer( data=data ) #elif model == 'packaging': # serializer = PackagingArticleSerializer( # data=data # ) elif model == 'embs': serializer = EMBSerializer( data=data ) elif model == 'manufacturingPlaces': serializer = ManufacturingPlacesSerializer( data=data ) elif model == 'originIngredients': serializer = OriginIngredientsSerializer( data=data ) if serializer.is_valid(): ingredients = serializer.save() elements.append(ingredients) else: elements.append(None) else: elements.append(None) return elements def fill_deeper_fields(self, article, validated_data): print(validated_data) brand_data = validated_data.pop('brand') if brand_data != None: serializer = BrandSerializer( data=brand_data ) if serializer.is_valid(): brand = serializer.save() article.brand = brand else: article.brand = None else: article.brand = None category_data = validated_data.pop('category') if category_data != None: serializer = CategorySerializer( data=category_data ) if serializer.is_valid(): category = serializer.save() article.category = category else: article.category = None else: article.category = None #data = validated_data.pop('ingredients') #elements = self.deserialize_multi_field(data, 'ingredients') #article.ingredients.set(elements) data = validated_data.pop('allergenes') elements = self.deserialize_multi_field(data, 'allergenes') article.allergenes.set(elements) data = validated_data.pop('traces') elements = self.deserialize_multi_field(data, 'traces') article.traces.set(elements) data = validated_data.pop('labels') elements = self.deserialize_multi_field(data, 'labels') article.labels.set(elements) #data = validated_data.pop('packaging') #elements = self.deserialize_multi_field(data, 'packaging') #article.packaging.set(elements) data = validated_data.pop('embs') elements = self.deserialize_multi_field(data, 'embs') article.embs.set(elements) data = validated_data.pop('manufacturingPlaces') elements = self.deserialize_multi_field(data, 'manufacturingPlaces') article.manufacturingPlaces.set(elements) data = validated_data.pop('originIngredients') elements = self.deserialize_multi_field(data, 'originIngredients') article.originIngredients.set(elements) return article # Problem: article_id is not readonly, therefore the serializer checks in validation for existence of article in order to create it, we have to prevent this class PurchaseArticlesSerializer(serializers.ModelSerializer): id = serializers.SerializerMethodField('pk') article_id = ArticleSerializer(read_only=True) #articleSer = ArticlesSerializer(article) sum_price = serializers.SerializerMethodField() map = serializers.SerializerMethodField() class Meta: model = PurchaseArticle fields = ('id','quantity','net_weight','price','inSale','article_id','purchase_id','sum_price','map') #depth = 2 def pk(self, obj): return obj.pk def get_sum_price(self, obj): return int(obj.quantity) * float(obj.price) def get_map(self, obj): purchaseImage = Purchase.objects.get(pk=obj.purchase_id).receipeImage #print(obj.article_id) articleMap = ArticleMaps.objects.get(article=obj.article_id, receipeImage=purchaseImage) print(articleMap) serializedMap = ArticleMapSerzializer(articleMap, many=False) return serializedMap.data def create(self, validated_data): print('create method of PurchaseArticlesSerializer') print(validated_data) #article = Article.objects.get(name=validated_data['article_id']['name'], # brand=validated_data['article_id']['brand'], # EAN=validated_data['article_id']['EAN'], # category=validated_data['article_id']['category']) articleArticle = PurchaseArticle.objects.create(purchase_id=validated_data.pop('purchase_id'), article_id=validated_data.pop('article_id'), quantity= validated_data.pop('quantity'), price = validated_data.pop('price'), inSale = validated_data.pop('inSale')) try: articleArticle.net_weight = validated_data.pop('net_weight') except KeyError: pass return articleArticle def to_internal_value(self, data): article_id = data.get('article_id') internal_data = super().to_internal_value(data) try: article = Article.objects.get(pk=article_id['pk']) except Article.DoesNotExist: raise ValidationError( {'article': ['Invalid article primary key']}, code='invalid', ) internal_data['article_id'] = article return internal_data #Serializer for nutrient model class NutrientSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk') pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) isMacroNutrient = serializers.BooleanField() def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `Nutrient` instance, given the validated data. """ #print("Nutrient:Create") try: return Nutrient.objects.create(**validated_data) except IntegrityError: return Nutrient.objects.get(name=validated_data['name']) def update(self, instance, validated_data): """ Update and return an existing `Nutrient` instance, given the validated data. """ #print("Labels:Update") instance.name = validated_data.get('name', instance.name) instance.save() return instance #Serializer for NutrientArticle model class NutrientArticleSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk',read_only=False) pk = serializers.IntegerField(read_only=False) article_id = serializers.IntegerField(source="article.pk") nutrient = NutrientSerializer() value = serializers.DecimalField(max_digits=7, decimal_places=2, allow_null = True) unit = serializers.CharField(max_length=4,allow_null = True) isEstimated = serializers.BooleanField(allow_null = True) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `NutrientArticle` instance, given the validated data. """ #print("NutrientArticle:Create") #print(validated_data) #try: article = Article.objects.get(pk=validated_data.pop('article')['pk']) nutrient = Nutrient.objects.get(pk=validated_data.pop('nutrient')['pk']) return PackagingArticle.objects.create(article=article, nutrient=nutrient, value=validated_data.pop('value'), unit=validated_data.pop('unit'), isEstimated=validated_data.pop('isEstimated') ) #except IntegrityError: # return PackagingArticle.objects.get(article_id=validated_data['article_id']) def update(self, instance, validated_data): #print('update method for articlepackaging') print(validated_data) print(instance) print(type(instance)) name = validated_data.pop('nutrient', instance.nutrient)['name'] nutrient = Nutrient.objects.get(name=name) instance.nutrient = nutrient instance.value = validated_data.pop('value',instance.value) instance.unit = validated_data.pop('unit',instance.unit) instance.isEstimated = validated_data.pop('isEstimated',instance.isEstimated) instance.save() return instance class PackagingArticleSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk',read_only=False) pk = serializers.IntegerField(read_only=False) #If we need the whole object: #article_id = ArticleSerializer() #otherwise, we just take the article primary key article_id = serializers.IntegerField(source="article_id.pk") packaging_id = PackagingSerializer() weight = serializers.IntegerField() def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `PackagingArticle` instance, given the validated data. """ print("PackagingArticle:Create") print(validated_data) #try: article = Article.objects.get(pk=validated_data.pop('article_id')['pk']) return PackagingArticle.objects.create(article_id=article, weight=validated_data.pop('weight')) #except IntegrityError: # return PackagingArticle.objects.get(article_id=validated_data['article_id']) def update(self, instance, validated_data): print('update method for articlepackaging') print(validated_data) #print(instance.packaging_id) name = validated_data.pop('packaging_id', instance.packaging_id)['name'] packaging = Packaging.objects.get(name=name) instance.packaging_id = packaging instance.weight = validated_data.pop('weight',instance.weight) instance.save() return instance class IngredientsArticleSerializer(serializers.Serializer): id = serializers.SerializerMethodField('pk',read_only=False) pk = serializers.IntegerField(read_only=False) #If we need the whole object: #article_id = ArticleSerializer() #otherwise, we just take the article primary key article = serializers.IntegerField(source="article.pk") ingredient = IngredientsSerializer() position = serializers.IntegerField() percent = serializers.FloatField(allow_null = True) def pk(self, obj): return obj.pk def create(self, validated_data): """ Create and return a new `IngredientsArticle` instance, given the validated data. """ print("IngredientsArticle:Create") print(validated_data) #try: article = Article.objects.get(pk=validated_data.pop('article')['pk']) return IngredientsArticle.objects.create(article=article, position=validated_data.pop('position')) #except IntegrityError: # return PackagingArticle.objects.get(article_id=validated_data['article_id']) def update(self, instance, validated_data): print('update method for articleingredient') print(validated_data) #print(instance.packaging_id) #ingredient_json = validated_data.pop('ingredient', instance.ingredient) ingredient = Ingredients.objects.get(id=self.initial_data['ingredient']['id']) instance.ingredient = ingredient instance.position = validated_data.pop('position',instance.position) instance.percent = validated_data.pop('percent',instance.percent) instance.save() return instance