from django.conf import settings from django.db import transaction from projects.models import Project from rest_flex_fields import FlexFieldsModelSerializer from rest_framework import serializers from rest_framework.exceptions import ValidationError from .models import Label, LabelLink class LabelListSerializer(serializers.ListSerializer): def validate(self, items): if len(set(item['project'] for item in items)) > 1: raise ValidationError('Creating labels for different projects in one request not allowed') return items def create(self, validated_data): """Bulk creation objects of Label model with related LabelLink reusing already existing labels """ from webhooks.utils import emit_webhooks_for_instance with transaction.atomic(): # loading already existing labels titles = [item['title'] for item in validated_data] existing_labels = Label.objects.filter( organization=self.context['request'].user.active_organization, title__in=titles ).all() existing_labels_map = {label.title: label for label in existing_labels} # create objects for labels, that we need to create labels_data = [] labels = [] labels_create = [] for item in validated_data: project = item.pop('project') from_name = item.pop('from_name') if item['title'] in existing_labels_map: label = existing_labels_map[item['title']] else: label = Label(**item) labels_create.append(label) labels.append(label) labels_data.append(dict(project=project, from_name=from_name)) if labels_create: if settings.DJANGO_DB == settings.DJANGO_DB_SQLITE: created_labels = {} for label in labels_create: label.save() created_labels[label.title] = label else: created_labels = {label.title: label for label in Label.objects.bulk_create(labels_create)} # connect existing and created labels to project with LabelLink links = [] result = [] for index, label in enumerate(labels): if label.id is None: label = created_labels[label.title] label.project = labels_data[index]['project'] label.from_name = labels_data[index]['from_name'] result.append(label) links.append( LabelLink( **{ 'label': label, 'project': labels_data[index]['project'], 'from_name': labels_data[index]['from_name'], } ) ) links = LabelLink.objects.bulk_create(links, ignore_conflicts=True) # webhooks processing # bulk_create with ignore_conflicts doesn't return ids, reloading links project = labels[0].project label_ids = [label.id for label in result] links = LabelLink.objects.filter(label_id__in=label_ids, project=project).all() if links: emit_webhooks_for_instance( self.context['request'].user.active_organization, links[0].project, 'LABEL_LINK_CREATED', links ) return result class LabelCreateSerializer(serializers.ModelSerializer): created_by = serializers.PrimaryKeyRelatedField(required=False, read_only=True) organization = serializers.PrimaryKeyRelatedField(required=False, read_only=True) project = serializers.PrimaryKeyRelatedField(queryset=Project.objects.all()) from_name = serializers.CharField() class Meta: model = Label list_serializer_class = LabelListSerializer fields = '__all__' class LabelLinkSerializer(FlexFieldsModelSerializer): annotations_count = serializers.IntegerField(read_only=True) class Meta: model = LabelLink fields = '__all__' expandable_fields = {'label': ('labels_manager.serializers.LabelSerializer', {'omit': ['links', 'projects']})} class LabelSerializer(FlexFieldsModelSerializer): links = serializers.PrimaryKeyRelatedField(many=True, read_only=True) class Meta: model = Label fields = '__all__' expandable_fields = {'links': ('labels_manager.serializers.LabelLinkSerializer', {'many': True})} class LabelBulkUpdateSerializer(serializers.Serializer): project = serializers.PrimaryKeyRelatedField(queryset=Project.objects.all(), required=False, default=None) old_label = serializers.JSONField() new_label = serializers.JSONField()