Django Rest Framework : Как определить ModelSerializer, представляющий модель A, когда A зависит от других моделей B и C?

Допустим, у нас есть три модели: МодельА, связанная с МодельюВ и МодельС.

МодельА определяется как :

class ModelA(models.Model):

    field_b = models.ForeignKey(ModelB, on_delete=models.CASCADE)
    field_c = models.ForeignKey(ModelC, on_delete=models.CASCADE)
    other_field = models.CharField(max_length=30)

    class Meta:
        constraints = [
                       models.UniqueConstraint(fields=['field_b', 'field_c'], name='unique_modelA')
                        ]
  • How to generate a ModelASerializer instance from instances of ModelB and ModelC ?
  • Then, will there be a serialized representation of field_b and field_c into ModelASerializer ?
  • The UniqueConstraint will it be checked when calling .is_valid() onto ModelASerializer instance ?

Я попробовал следующее :

class ModelASerializer(serializers.ModelSerializer):
        field_b = ModelBSerializer(read_only=True)
        field_c = ModelCSerializer(read_only=True)
        other_field = serializers.CharField(required=False)

        class Meta:
            model = ModelA
            fields = ('field_b', 'field_c', 'other_field',)
            validators = [
                        UniqueTogetherValidator(
                            queryset=ModelA.objects.all(),
                            fields=['field_b', 'field_c'],
                            message='A Model A instance for this couple of ModelB and ModelC instances already exists.'
                        )
                    ]

    def create(self, validated_data):
        """
        Create and return a new `ModelA` instance, given the validated data.
        """
        return ModelA.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `ModelA` instance, given the validated data.
        """
        instance.other_field= validated_data.get('other_field', instance.other_field)
        instance.save()
        return instance

Но я не могу найти способ создания сериализатора :

model_b = ModelB()
model_c = ModelC()
model_b.save()
model_c.save()
other_field = "Dummy content"

Первая попытка

model_a_serializer = ModelASerializer(model_b, model_c, other_field)
  • The serializer is looking for an ID field and can't find it
  • Anyway, no data field being provided, we can't call .is_valid() onto the serializer, and thus, can't check the integrity constraint

Вторая попытка

.
model_b_serializer = ModelBSerializer(model_b)
model_c_serializer = ModelCSerializer(model_c)
data = {'model_b':model_b_serializer , 'model_c':model_c_serializer , 'other_field':other_field}

model_a_serializer = ModelASerializer(data=data)
if model_a_serializer.is_valid():
    model_a_serializer.save()

Здесь сериализатор пытается заново создать экземпляры ModelB и ModelC при вызове is_valid()... А я этого не хочу.

Есть идеи? Заранее большое спасибо.

Не уверен, правильно ли я понял ваш вопрос, но...

  • Как создать экземпляр ModelASerializer из экземпляров ModelB и ModelC ?

Если вы хотите создать экземпляр ModelA из ModelB и ModelC, то вам следует удалить аргумент read_only=True и явно указать отношения в методе create и update.

class ModelBSerializer(serializers.ModelSerializer):
    modelA_set = ModelASerializer() # this field name can be changed by adding related_name attribute in ModelA in models.py
    class Meta:
        model = ModelB
        fields = ('modelA_set' , 'other_fields')
    
    def create(self,validate_data):
        modelA_data = validate_data.pop('modelA_data') # whatever field name you will use to send data for modelA
        b = ModelB.objects.create(**validate_data)
        for data in modelA_data:
            modelA_instance  = ModelA.objects.create(field_b=b ,**data)
        return b

modelA_set - это автоматически генерируемое имя поля, когда мы пытаемся сериализовать ModelA из сериализатора ModelB. Его можно изменить, передав аргумент related_name='some_name' следующим образом:

field_b = models.ForeignKey(ModelB, on_delete=models.CASCADE , related_name="field_a")

  • Тогда, будет ли сериализованное представление поля_b и поля_c в ModelASerializer ?

Да, будет.

Еще раз поправьте меня, если я неправильно понял ваш вопрос.
Вернуться на верх