Custom relation field for django-rest-framework's serializers
Project description
DRF Custom Related Field
This is a Django REST Framework's PrimaryKeyRelatedField
like field which
allows you to pass custom fields (instead of default pk) to serialize relation.
Requirements
- Python 3.6+
- Django 2+
- djangorestframework 3+
Installation
pip install drf-custom-related-field
Usage
For example, we have following model structure:
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
country = models.CharField(max_length=100)
def upper_name(self):
return self.name.upper()
class Address(models.Model):
street = models.CharField(max_length=255)
building = models.CharField(max_length=255)
def full_address(self):
return f'{self.street}, {self.building}'
class WorkingBuilding(models.Model):
capacity = models.IntegerField(default=0)
address = models.ForeignKey(Address, on_delete=models.CASCADE)
class Employee(models.Model):
username = models.CharField(max_length=100)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
workplace = models.ForeignKey(WorkingBuilding, null=True, on_delete=models.CASCADE, related_name='employees')
And we have following instances:
work_address = Address.objects.create(street='Main st.', building='10')
workplace = WorkingBuilding.objects.create(capacity=200, address=work_address)
company = Company.objects.create(name='Great Inc.', country='US', )
employee = Employee.objects.create(username='ckkz', company=company, workplace=workplace)
Examples:
-
Map custom field for read only
class EmployeeSerializer(serializers.ModelSerializer): company = CustomRelatedField(queryset=Company.objects, field_name='name') class Meta: model = Employee fields = ('username', 'company') serializer = EmployeeSerializer(employee) assert serializer.data['company'] == company.name
{ "username": "ckkz", "company": "Great Inc." }
-
Assign new value by custom field (
name
in this case)class EmployeeSerializer(serializers.ModelSerializer): company = CustomRelatedField(queryset=Company.objects, field_name='name') class Meta: model = Employee fields = ('username', 'company') new_company = Company.objects.create(name='New Company', country='RU') serializer = EmployeeSerializer(employee, data={'company': new_company.name}, partial=True) serializer.is_valid(raise_exception=True) serializer.save() employee.refresh_from_db() assert employee.company_id == new_company.id
{ "username": "ckkz", "company": "New Company" }
-
Use
many=True
class WorkingBuildingSerializer(serializers.ModelSerializer): employees = CustomRelatedField(field_name='username', many=True, read_only=True) class Meta: model = WorkingBuilding fields = ('capacity', 'employees') serializer = WorkingBuildingSerializer(workplace) assert len(serializer.data['employees']) == workplace.employees.count()
{ "capacity": 200, "employees": ["ckkz"] }
-
Use nested (dotted) relations and callable model fields
class EmployeeSerializer(serializers.ModelSerializer): workplace = CustomRelatedField(source='workplace.address', field_name='full_address', read_only=True) class Meta: model = Employee fields = ('username', 'workplace') serializer = EmployeeSerializer(employee) assert serializer.data['workplace'] == employee.workplace.address.full_address()
{ "username": "ckkz", "workplace": "Main st., 10" }
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.