Как сделать поле StringRelatedField, доступное только для чтения и объявленное как ForeignKey, доступным для пост-запросов?

У меня есть следующие два класса моделей в django rest framework

class Customer(models.Model):
    GENDER_CHOICES = [
    ('Male', 'Male'),
    ('Female', 'Female'),
   ] 
    customer_id = models.AutoField(primary_key=True)
    firstname = models.CharField(max_length=20)
    lastname = models.CharField(max_length=30) 
    gender = models.CharField(max_length=6, choices=GENDER_CHOICES)
    date_of_birth = models.DateField()
    nationality = models.CharField(max_length=50, null=False)
    id_card_number = models.CharField(max_length=20, unique=True)
    passport_number = models.CharField(max_length=20, unique=True)
    address = models.CharField(max_length=100)
    phone_number = models.CharField(max_length=20)
    email = models.EmailField(max_length=254,null=True, blank=True, unique=True)
    
    def __str__(self):
        return f"{self.firstname} {self.lastname}"
    
    
class Contract(models.Model):    
    INSURANCE_TYPE_CHOICES = [
        ('Health', 'Health Insurance'),
        ('Life', 'Life Insurance'),
        ('Auto', 'Auto Insurance'),
        ('Home', 'Home Insurance'),
    ]
    
    contract_number = models.AutoField(primary_key=True)
    start_date = models.DateField()
    end_date = models.DateField()
    insurance_type = models.CharField(max_length=15, choices=INSURANCE_TYPE_CHOICES)    
    insurance_holder = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="contracts")
    active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
     
    
    def __str__(self):
        return f"{self.contract_number} {self.insurance_type}"

и следующие два сериализатора

class ContractSerializer(serializers.ModelSerializer):
    
    insurance_holder = serializers.StringRelatedField(read_only=True)
   
    class Meta:
        model = Contract
        exclude = ("updated_at",) 
    

class CustomerSerializer(serializers.ModelSerializer):
    
    contracts = ContractSerializer(many=True, read_only=True)   
    
    class Meta:
        model = Customer
        fields = "__all__"

Я также создал свои конечные точки url и представления, я протестировал свой api через Postman и встроенный django-rest browasable API и все в порядке, но у меня возникла следующая проблема.

Держатель страховки является внешним ключом моей модели клиентов, поэтому, когда я получаю запросы в конечной точке контрактов, я получаю Id вместо полного имени, поэтому я установил держателя страховки в сериализаторе как StringRelatedField, чтобы получить полное имя, однако это поле только для чтения, поэтому я не могу отправлять запросы в контракты с полным именем. Как я могу сделать пост-запросы с именем, но сохранить ограничение внешнего ключа моделей.

Кстати, я новичок в Django и Django Rest Framework, да и вообще новичок.

Я уже прочитал документацию django rest о связанных полях и следующий пост stack overflow Как я могу показать StringRelatedField вместо Primary Key, сохраняя возможность записи в это поле с помощью Django Rest Framework? но я все еще не понимаю, как решить эту проблему.

Самым простым решением будет переопределить to_representation метод сериализации сериализатора и заменить возвращаемое значение, не изменяя исходное поле:

class ContractSerializer(serializers.ModelSerializer):

    class Meta:
        model = Contract
        exclude = ("updated_at",)

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation["insurance_holder"] = str(instance.insurance_holder)
        return representation
Вернуться на верх