From 8059cd3667dfc39a705e50c174602bfbb2bf47a8 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 25 Jan 2021 13:51:38 +0000 Subject: [PATCH] more tests for tagging serializer --- products/serializers.py | 2 +- products/tests.py | 2 +- requirements.txt | 3 +- utils/tag_serializers.py | 72 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/products/serializers.py b/products/serializers.py index a1e0832..42e3d8a 100644 --- a/products/serializers.py +++ b/products/serializers.py @@ -6,7 +6,7 @@ from products.models import Product from utils.tag_serializers import SingleTagSerializerField, CustomTagSerializer -class ProductSerializer(CustomTagSerializer, serializers.ModelSerializer): +class ProductSerializer(CustomTagSerializer): tags = TagListSerializerField(required=False) category = SingleTagSerializerField(required=False) # main tag category diff --git a/products/tests.py b/products/tests.py index 3f77e89..da69855 100644 --- a/products/tests.py +++ b/products/tests.py @@ -118,7 +118,7 @@ class ProductViewSetTest(APITestCase): 'stock': 22, 'tags': ['tag1, tag2'], # 'category': 'MayorTagCategory', - # 'attributes': ['color/red', 'size/xxl'], + 'attributes': ['color/red', 'size/xxl'], 'identifiers': '34rf34f43c43', } diff --git a/requirements.txt b/requirements.txt index c2f2832..0e62195 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ django-dotenv==1.4.2 django-filter==2.4.0 -e git://github.com/darklow/django-suit/@v2#egg=django-suit django-cors-headers==3.5.0 -django-taggit-serializer==0.1.7 \ No newline at end of file +django-taggit-serializer==0.1.7 +django-tagulous==1.1.0 \ No newline at end of file diff --git a/utils/tag_serializers.py b/utils/tag_serializers.py index 49dca92..6a9a72d 100644 --- a/utils/tag_serializers.py +++ b/utils/tag_serializers.py @@ -1,4 +1,11 @@ +import traceback + from rest_framework import serializers +from rest_framework.fields import CharField, ListField +from rest_framework.serializers import raise_errors_on_nested_writes +from rest_framework.utils import model_meta + +from tagulous.models.descriptors import FakeTagRelatedManager from taggit_serializer.serializers import TagListSerializerField, TaggitSerializer @@ -40,14 +47,67 @@ class SingleTagSerializerField(serializers.Field): return value -class CustomTagSerializer(serializers.Serializer): +class CustomTagSerializer(serializers.ModelSerializer): + """ + Differentiate between tags and single-tags + """ + + def __init__(self, instance=None, data='', **kwargs): + self.serializer_field_mapping[SingleTagSerializerField] = CharField + self.serializer_field_mapping[TagListSerializerField] = ListField + super(CustomTagSerializer, self).__init__(instance, data, **kwargs) def create(self, validated_data): to_be_tagged, validated_data = self._pop_tags(validated_data) - tag_object = super(CustomTagSerializer, self).create(validated_data) + # tag_object = super(CustomTagSerializer, self).create(validated_data) + raise_errors_on_nested_writes('create', self, validated_data) - return self._save_tags(tag_object, to_be_tagged) + ModelClass = self.Meta.model + + # Remove many-to-many relationships from validated_data. + # They are not valid arguments to the default `.create()` method, + # as they require that the instance has already been saved. + info = model_meta.get_field_info(ModelClass) + many_to_many = {} + for field_name, relation_info in info.relations.items(): + if relation_info.to_many and (field_name in validated_data): + many_to_many[field_name] = validated_data.pop(field_name) + + try: + instance = ModelClass._default_manager.create(**validated_data) + except TypeError: + tb = traceback.format_exc() + msg = ( + 'Got a `TypeError` when calling `%s.%s.create()`. ' + 'This may be because you have a writable field on the ' + 'serializer class that is not a valid argument to ' + '`%s.%s.create()`. You may need to make the field ' + 'read-only, or override the %s.create() method to handle ' + 'this correctly.\nOriginal exception was:\n %s' % + ( + ModelClass.__name__, + ModelClass._default_manager.name, + ModelClass.__name__, + ModelClass._default_manager.name, + self.__class__.__name__, + tb + ) + ) + raise TypeError(msg) + + # Save many-to-many relationships after the instance is created. + if many_to_many: + for field_name, value in many_to_many.items(): + field = getattr(instance, field_name) + import ipdb; ipdb.set_trace() + if type(field) == "": + for item in value: + field.set(item) + else: + field.set(value) + + return self._save_tags(instance, to_be_tagged) def update(self, instance, validated_data): to_be_tagged, validated_data = self._pop_tags(validated_data) @@ -66,12 +126,10 @@ class CustomTagSerializer(serializers.Serializer): def _pop_tags(self, validated_data): to_be_tagged = {} - import ipdb; ipdb.set_trace() - for key in self.fields.keys(): - field = self.fields[key] + for key in self.serializer_field_mapping.keys(): + field = self.serializer_field_mapping[key] if isinstance(field, TagListSerializerField): if key in validated_data: to_be_tagged[key] = validated_data.pop(key) return (to_be_tagged, validated_data) -