Django Rest api json imput для m-m отношений

Я пытаюсь разместить json файл и сохранить модели в базу данных. AttributeName и AttributeValue генерируются правильно, но Attribute сохраняется без "nazev_atributu_id" и "hodnota_atributu_id".

[     
    
  {
    "AttributeName": {
      "id": 2,
      "nazev": "Barva"
    }
  },
  {
    "AttributeValue": {
      "id": 2,
      "hodnota": "modrá"
    }
  },

  {
    "Attribute": {
      "id": 1,
      "nazev_atributu_id": 2,
      "hodnota_atributu_id": 2
    }
  }
]

models.py

from django.db import models


class AttributeValue(models.Model):
    unique_id = models.AutoField(primary_key=True)
    id = models.IntegerField(unique=True)
    hodnota = models.CharField(max_length=255, null=True, blank=True)

    def __str__(self):
        return f"AttributeValue with id: {self.id}"


class AttributeName(models.Model):
    unique_id = models.AutoField(primary_key=True)
    id = models.IntegerField()
    nazev = models.CharField(max_length=255, null=True, blank=True)
    kod = models.CharField(max_length=255, null=True, blank=True)
    zobrazit = models.BooleanField(default=False)

    def __str__(self):
        return f"AttributeName with id: {self.id}"


class Attribute(models.Model):
    unique_id = models.AutoField(primary_key=True)
    id = models.IntegerField(unique=True)
    nazev_atributu_id = models.ManyToManyField(AttributeName, through='AttributeAttributeNameMapping')
    hodnota_atributu_id = models.ManyToManyField(AttributeValue, through='AttributeAttributeValueMapping')

    def __str__(self):
        return f"Attribute with id: {self.id}"


class AttributeAttributeNameMapping(models.Model):
    attribute = models.ForeignKey(Attribute, on_delete=models.CASCADE)
    attribute_name = models.ForeignKey(AttributeName, on_delete=models.CASCADE)

    class Meta:
        unique_together = ('attribute', 'attribute_name')


class AttributeAttributeValueMapping(models.Model):
    attribute = models.ForeignKey(Attribute, on_delete=models.CASCADE)
    attribute_value = models.ForeignKey(AttributeValue, on_delete=models.CASCADE)

    class Meta:
        unique_together = ('attribute', 'attribute_value')

serializer

from rest_framework import serializers
from .models import *

class AttributeNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = AttributeName
        fields = '__all__'


class AttributeValueSerializer(serializers.ModelSerializer):
    class Meta:
        model = AttributeValue
        fields = '__all__'


class AttributeSerializer(serializers.ModelSerializer):
    nazev_atributu_id = serializers.SlugRelatedField(queryset=AttributeName.objects.all(),slug_field='id')
    hodnota_atributu_id = serializers.SlugRelatedField(queryset=AttributeValue.objects.all(),slug_field='id')

    class Meta:
        model = Attribute
        fields = ["unique_id", "id", "nazev_atributu_id", "hodnota_atributu_id"]

    def create(self, validated_data):
        # Extract many-to-many fields from the validated data
        print("**************************")
        print(validated_data)
        print("**************************")
        nazev_atributu_id = validated_data.pop('nazev_atributu_id')
        hodnota_atributu_id = validated_data.pop('hodnota_atributu_id')
        # Create the Attribute instance
        attribute = Attribute.objects.create(**validated_data)
        print("???????????????????")
        print(nazev_atributu_id.__dict__)
        print(hodnota_atributu_id.__dict__)
        print("?????????????")
        print(attribute, type(attribute))
        print(attribute.__dict__)
        print("------------------")
        print(attribute.nazev_atributu_id)
        print(attribute.hodnota_atributu_id)
        print("------------------")
        # Set many-to-many relationships
        attribute.nazev_atributu_id.add(nazev_atributu_id)
        attribute.hodnota_atributu_id.add(hodnota_atributu_id)
        print("////////////////////")
        print(attribute.__dict__)
        print("////////////////////")
        return attribute

Но все еще не могу понять, почему атрибуты одинаковы до и после

    attribute.nazev_atributu_id.add(nazev_atributu_id)
    attribute.hodnota_atributu_id.add(hodnota_atributu_id)

Вот вывод на печать после вызова post-запроса:

**************************
{'id': 1, 'nazev_atributu_id': <AttributeName: AttributeName with id: 2>, 'hodnota_atributu_id': <AttributeValue: AttributeValue with id: 2>}
**************************
???????????????????
{'_state': <django.db.models.base.ModelState object at 0x000001E7E56E99D0>, 'unique_id': 206, 'id': 2, 'nazev': 'Barva', 'kod': None, 'zobrazit': False}
{'_state': <django.db.models.base.ModelState object at 0x000001E7E56E9070>, 'unique_id': 214, 'id': 2, 'hodnota': 'modrá'}
?????????????
Attribute with id: 1 <class 'api.models.Attribute'>
{'_state': <django.db.models.base.ModelState object at 0x000001E7E56E9310>, 'unique_id': 78, 'id': 1}
------------------
api.AttributeName.None
api.AttributeValue.None
------------------
////////////////////
{'_state': <django.db.models.base.ModelState object at 0x000001E7E56E9310>, 'unique_id': 78, 'id': 1}
////////////////////

Просмотров

Использование пользовательского BaseManyToManySerializer:

class BaseManyToManySerializer(serializers.ModelSerializer):

    def to_internal_value(self, data):
        data = dict(data)
        for field_name, model_class in self.get_id_conversion_mappings():
            self._convert_ids_to_unique_ids(data, field_name, model_class)
        return super().to_internal_value(data)

    def _convert_ids_to_unique_ids(self, data, field_name, model_class):
        if field_name in data:
            ids = data.get(field_name)
            if not isinstance(ids, list):
                ids = [ids]
            objects = model_class.objects.filter(id__in=ids)
            id_map = {}
            for obj in objects:
                if obj.id not in id_map:
                    id_map[obj.id] = []
                id_map[obj.id].append(obj.unique_id)
            data[field_name] = [unique_id for id in ids for unique_id in id_map.get(id, [])]

    def create(self, validated_data):
        many_to_many_data = {field_name: validated_data.pop(field_name, []) for field_name, field_class in
                             self.get_many_to_many_fields()}
        instance = self.Meta.model.objects.create(**validated_data)
        for field_name, field_class in self.get_many_to_many_fields():
            if field_name in many_to_many_data:
                field_value = many_to_many_data[field_name]
                if hasattr(instance, field_name):
                    getattr(instance, field_name).set(field_value)
        return instance

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        for field_name, field_class in self.get_many_to_many_fields():
            if hasattr(instance, field_name):
                representation[field_name] = [item.id for item in getattr(instance, field_name).all()]
        return representation

    def get_id_conversion_mappings(self):
        raise NotImplementedError("Subclasses must implement this method.")

    def get_many_to_many_fields(self):
        raise NotImplementedError("Subclasses must implement this method.")

Использование сотворения мира:

class AttributeSerializer(BaseManyToManySerializer):
    nazev_atributu_id = serializers.PrimaryKeyRelatedField(queryset=AttributeName.objects.all(), many=True,
                                                           required=False)
    hodnota_atributu_id = serializers.PrimaryKeyRelatedField(queryset=AttributeValue.objects.all(), many=True,
                                                             required=False)

    class Meta:
        model = Attribute
        fields = ["unique_id", "id", "nazev_atributu_id", "hodnota_atributu_id"]

    def get_id_conversion_mappings(self):
        return [
            ('nazev_atributu_id', AttributeName),
            ('hodnota_atributu_id', AttributeValue)
        ]

    def get_many_to_many_fields(self):
        return [
            ('nazev_atributu_id', AttributeName),
            ('hodnota_atributu_id', AttributeValue)
        ]
Вернуться на верх