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 ?
Да, будет.