Skip to content
Advertisement

DRF – Relate an object to another using views, serializers and foreign key

Basically I have two models with one-to-one relationship. And I want retrieve information from one, when I call the other.

My models:

class Customer(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)    


class CurrentAccount(models.Model):
    customer_account = models.ForeignKey(Customer, on_delete=models.CASCADE, 
    related_name='customer_account', blank=True, null=True)
    balance = models.FloatField()

So I can just call an POST and create an Customer, that customer will have id, first_name and last_name. For now everything is working.

But when I try to call my endpoint to create an CurrentAccount informing my Customer to relate, nothing happens.

My input:

{
    "customer_account": 1 #this is some id from an Customer that is already created,
    "balance": 0.0
}

The output that I expected:

{
    "id": 42,
    "customer_account": {
        "id": 2,
        "first_name": "Michele",
        "last_name": "Obama"
    }
    "balance": 0.0
}

The output that I received:

{
    "id": 4,
    "balance": 0.0
}

As you can see, Django are ignoring the relationship (In the database the field ‘customer_account_id’ is null too, so isn’t just an problem with my return).

Here is my serializers:

class CustomerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = ('id', 'first_name', 'last_name')


class CurrentAccountSerializer(serializers.ModelSerializer):
    customer_account = CustomerSerializer(read_only=True)
    class Meta:
        model = CurrentAccount
        fields = ('id', 'customer_account', 'balance')

And my views to create the CurrentAccount:

@api_view(['GET', 'POST'])
def currentaccount_list_view(request):

    if request.method == 'GET':
        try:
            data = CurrentAccount.objects.all()
            ser = CurrentAccountSerializer(data, many=True)
            return response_success(data=ser.data)
        except Exception as e:
            return response_failed(e.args)
            
    elif request.method == 'POST':
        try:
            ser = CurrentAccountSerializer(data=request.data, context={'request': request})
            if ser.is_valid():
                ser.save()
                return response_success(data=ser.data)
            else:
                return response_failed('Something wrong with the input data')
        except Exception as e:
            return response_failed(e.args)

So I basically want to understand how the relationships works on Django and how to handle with DRF context, using serializers. I already looked the docs, but I still not understanding.

Advertisement

Answer

The problem is with the CurrentAccountSerializer serializer, you set the customer_account field as read only. You should also use two serializers with CurrentAccount, the first to list existing instances and the second to create new ones.

serializers

class CustomerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = ('id', 'first_name', 'last_name')


class CurrentAccountInfoSerializer(serializers.ModelSerializer):
    customer_account = CustomerSerializer(read_only=True)

    class Meta:
        model = CurrentAccount
        fields = ('id', 'customer_account', 'balance')


class CurrentAccountCreationSerializer(serializers.ModelSerializer):
    customer_account = serializers.PrimaryKeyRelatedField(queryset=Customer.objests.all())

    class Meta:
        model = CurrentAccount
        fields = ('id', 'customer_account', 'balance')

    def create(self, validated_data):
        return CurrentAccount.objects.create(**validated_data)

views

@api_view(['GET', 'POST'])
def currentaccount_list_view(request):
    if request.method == 'GET':
        try:
            data = CurrentAccount.objects.all()
            ser = CurrentAccountInfoSerializer(data, many=True)
            return response_success(data=ser.data)
        except Exception as e:
            return response_failed(e.args)
            
    elif request.method == 'POST':
        try:
            ser = CurrentAccountCreationSerializer(data=request.data, context={'request': request})
            if ser.is_valid():
                instance = ser.save()
                return response_success(data=CurrentAccountInfoSerializer(instance=instance).data)
            else:
                return response_failed('Something wrong with the input data')
        except Exception as e:
            return response_failed(e.args)
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement