PrimaryKeyRelatedField

PrimaryKeyRelatedField represents the target of the relation using the primary key (pk). It can be achieved by generating the relationship using the rest_framework.serializers.PrimaryKeyRelatedField() field. By default, this field is read-write, but you can make it read-only by setting the read_only attribute to True. The PrimaryKeyRelatedField has the following arguments:

  • queryset – It used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly (serializers.PrimaryKeyRelatedField(queryset=Employee.objects.all(),many=False) ), or set read_only=True.
  • many – Set this argument to True to serialize more than one relationship
  • allow_null – If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.
  • pk_field – Set to a field to control serialization/deserialization of the primary key’s value. For example, pk_field=UUIDField(format=’hex’) would serialize a UUID primary key into its compact hex representation.

Now let’s get to our serializer code. Here we have two serializer classes — EmployeeSerializer and EmployeeTaskSerializer. The EmployeeSerializer class serializes the Employee model and the EmployeeTaskSerializer serializes the EmployeeTask model. The EmployeeTask Model holds a ManyToOne relationship with the Employee Model. 

employee = models.ForeignKey(Employee,
                                  related_name='tasks',
                                  on_delete=models.CASCADE)

The same task will not be assigned to more than one employee, but one employee can have multiple tasks. Hence, the EmployeeTaskSerializer class should serialize only a single employee instance, whereas, EmployeeSerializer class should serialize one or more EmployeeTask instances (more than one task can be assigned to an employee).

The relationship generator process in EmployeeTaskSerializer as follows:

employee = serializers.PrimaryKeyRelatedField(queryset=Employee.objects.all(),
                                                  many=False) 

By default, the PrimaryKeyRelatedField field has read-write permission. The queryset=Employee.objects.all() argument checks for the particular model instance in the Employee table. The many=False argument is set because there is only a single relationship to serialize.

The relationship generator process in EmployeeSerializer class as follows:

tasks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

The tasks attribute is the related_name specified (ForeignKey relationship) in the EmployeeTask model. Since each employee can have more than one task we set many=True. The read_only=True only allows permission to retrieve the EmployeeTask. 

You can add the below code to the serializers.py file. (if you don’t have the file, you can create a file named serializers.py file in your app [employees] folder).

Python3




from rest_framework import serializers
from employees.models import Employee, EmployeeTask
  
class EmployeeSerializer(serializers.ModelSerializer):
    # PrimaryKeyRelatedField
    tasks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
  
    class Meta:
        model = Employee
        fields = (
            'pk',
            'emp_id',
            'name',
            'gender',
            'designation',
            'tasks')
  
  
class EmployeeTaskSerializer(serializers.ModelSerializer):
    # PrimaryKeyRelatedField
    employee = serializers.PrimaryKeyRelatedField(queryset=Employee.objects.all(),
                                                  many=False)     
  
    class Meta:
        model = EmployeeTask
        fields = (
            'pk',
            'task_name',
            'employee',
            'task_desc',
            'created_date',
            'deadline')


Let’s populate the employee table. You can execute the below HTTPie command.

http POST :8000/employees/ emp_id=128 name=”Mathew A” gender=”M” designation=”Software Engineer”

Output

HTTP/1.1 201 Created
Content-Length: 140
Content-Type: application/json
Date: Thu, 21 Jan 2021 09:16:50 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "designation": "Software Engineer",
    "emp_id": 128,
    "gender": "M",
    "name": "Mathew A",
    "pk": 8,
    "tasks": []
}

You can notice the pk value of the employee. Now, let’s create an employee task and map it to the employee using PrimaryKeyRelatedField. Here the primary key value of the employee named Mathew A is 8. You have to pass it to the field name employee.  Execute the below HTTPie command.

http :8000/task/ task_name=”Interchange first and last elements in a list” employee=8 task_desc=”Write a Python program to interchange first and last element in a list” deadline=”2021-01-25 00:00:00.000000+00:00″ 

Output

HTTP/1.1 201 Created
Content-Length: 285
Content-Type: application/json
Date: Thu, 21 Jan 2021 09:42:39 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "created_date": "2021-01-21T09:42:39.792788Z",
    "deadline": "2021-01-25T00:00:00Z",
    "employee": 8,
    "task_desc": "Write a Python program to interchange first and last element in a list",
    "task_name": "Interchange first and last elements in a list"
}

You can create one more task and assign it to the same employee and process the request to retrieve the employee details. The HTTPie command is 

http :8000/employees/

Output

HTTP/1.1 200 OK
Content-Length: 219
Content-Type: application/json
Date: Fri, 22 Jan 2021 03:58:01 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "designation": "Software Engineer",
        "emp_id": 128,
        "gender": "M",
        "name": "Mathew A",
        "pk": 8,
        "tasks": [
            2,
            1
        ]
    },
    {
        "designation": "Test Engineer",
        "emp_id": 129,
        "gender": "F",
        "name": "Jeena R",
        "pk": 9,
        "tasks": []
    }
]

Sharing the command prompt screenshot for your reference

You can notice the tasks field for the employee named Mathew A. It displays the pk of the task model and the many=True argument serialized multiple task instance id.

Let’s retrieve the task details using the below HTTPie command

http :8000/task/

Output

HTTP/1.1 200 OK
Content-Length: 454
Content-Type: application/json
Date: Fri, 22 Jan 2021 03:59:40 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "created_date": "2021-01-21T09:48:47.710707Z",
        "deadline": "2021-01-27T00:00:00Z",
        "employee": 8,
        "pk": 2,
        "task_desc": "Write a Python program for Binary Search",
        "task_name": "Binary Search"
    },
    {
        "created_date": "2021-01-21T09:42:39.792788Z",
        "deadline": "2021-01-25T00:00:00Z",
        "employee": 8,
        "pk": 1,
        "task_desc": "Write a Python program to interchange first and last element in a list",
        "task_name": "Interchange first and last elements in a list"
    }
]

Sharing the command prompt screenshot for your reference

 Let’s look at the HTTPie command to create a new task.

http :8000/task/ task_name=”PrimaryKeyRelatedField” employee=8 task_desc=”Serialize relationship using PrimaryKeyRelateField” deadline=”2021-01-27 00:00:00.000000+00:00″

Output

HTTP/1.1 201 Created
Content-Length: 213
Content-Type: application/json
Date: Fri, 22 Jan 2021 04:33:15 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "created_date": "2021-01-22T04:33:15.855264Z",
    "deadline": "2021-01-27T00:00:00Z",
    "employee": 8,
    "pk": 6,
    "task_desc": "Serialize relationship using PrimaryKeyRelateField",
    "task_name": "PrimaryKeyRelatedField"
}

Sharing the command prompt screenshot for your reference:

 Now let’s explore how StringRelatedField represents a relationship. 

Serializer Relations – Django REST Framework

Serialization is one of the most important concepts in RESTful Webservices.  It facilitates the conversion of complex data (such as model instances) to native Python data types that can be rendered using JSON, XML, or other content types. In Django REST Framework, we have different types of serializers to serialize object instances, and the serializers have different serializer relations to represent model relationships. In this section, we will discuss the different serializer relations provided by Django REST Framework Serializers. 

Table of Contents

  • Getting Started
  • Creating Django Models and Views
  • PrimaryKeyRelatedField
  • StringRelatedField
  • SlugRelatedField
  • HyperlinkedIndetityField
  • HyperlinkedRelatedField
  • Nested Relationship

Similar Reads

Getting Started

Before working on Django REST Framework serializers, you should make sure that you already installed Django and Django REST Framework in your virtual environment. You can check the below tutorials:...

Creating Django Models and Views

Creating Django Models...

PrimaryKeyRelatedField

...

StringRelatedField

...

SlugRelatedField

...

HyperlinkedIndetityField

...

HyperlinkedRelatedField

...

Nested Relationship

PrimaryKeyRelatedField represents the target of the relation using the primary key (pk). It can be achieved by generating the relationship using the rest_framework.serializers.PrimaryKeyRelatedField() field. By default, this field is read-write, but you can make it read-only by setting the read_only attribute to True. The PrimaryKeyRelatedField has the following arguments:...

Contact Us