Taxonomy is the science of defining and naming groups of biological organisms on the basis of shared characteristics. Organisms are grouped together into taxa (singular: taxon) and these groups are given a taxonomic rank. The principal ranks in modern use are domain, kingdom, phylum, class, order, family, genus and species. More information on Taxonomy and Taxonomic ranks in Wikipedia.
Following the example for the red fox in the article Taxonomic rank in Wikipedia I need to create a JSON output like this:
{
"species": "vulpes",
"genus": "Vulpes",
"family": "Canidae",
"order": "Carnivora",
"class": "Mammalia",
"phylum": "Chordata",
"kingdom": "Animalia",
"domain": "Eukarya"
}
Since Django REST Framework creates the keys based on the field names, the problem arises with the taxonomic rank class (bold in the example) as it is a reserved word in Python and can't be used as a variable name.
A model class created in Django would look like this:
class Species(models.Model):
species = models.CharField()
genus = models.CharField()
family = models.CharField()
# class = models.CharField() - class is reserved word in Python
# class_ = models.CharField() - Django doesn't allow field names
# ending with underscore. That wouldn't be either a satisfying solution.
# further fields
Is there any possible way to solve this problem and generate the desired output? If not, what is the best practice to work around this problem?
Answer is Simply No, Because Language only has the authority to own anything. Python is the owner of the house The Django guy is paying rent to Python guy.
From DRF v3 onwards, setting a field as read-only or write-only can use serializer field core arguments mentioned as follows. write_only. Set this to True to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.
JSON Web Token (JWT) Authentication.
Django is the web development framework in python whereas the Django Rest Framework is the library used in Django to build Rest APIs. Django Rest Framework is especially designed to make the CRUD operations easier to design in Django. Django Rest Framework makes it easy to use your Django Server as an REST API.
You can set the property of a class via strings as such:
class SpeciesSerializer(serializers.Serializer):
species = serializers.CharField()
genus = serializers.CharField()
family = serializers.CharField()
vars()['class'] = serializers.CharField()
You can rename field in the overloaded version of get_fields()
method
class MySerializer(serializers.Serializer):
class_ = serializers.ReadOnlyField()
def get_fields(self):
result = super().get_fields()
# Rename `class_` to `class`
class_ = result.pop('class_')
result['class'] = class_
return result
You can do it like below
class SpeciesSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Species
fields = (
'url', 'id', 'canonical_name', 'slug', 'species', 'genus',
'subfamily', 'family', 'order','class', 'phylum',
'ncbi_id', 'ncbi_taxonomy',
)
read_only_fields = ('slug',)
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
SpeciesSerializer._declared_fields["class"] = serializers.CharField(source="class_name")
As explained in below answer
https://stackoverflow.com/a/47717441/2830850
Other software developers in the field of Bioinformatics might be interested in a solution of this problem, so I post here my approach as suggested by Alasdair.
The goal is to create a model for a living species, for the sake of simplicity let's say an animal, and create an endpoint with Django REST Framework representing the correct taxonomic ranks.
models.py
from django.db import models
class Animal(models.Model):
canonical_name = models.CharField(max_length=100, unique=True)
species = models.CharField(max_length=60, unique=True)
genus = models.CharField(max_length=30)
family = models.CharField(max_length=30)
order = models.CharField(max_length=30)
# we can't use class as field name
class_name = models.CharField('Class', db_column='class', max_length=30)
phylum = models.CharField(max_length=30)
# we don't need to define kingdom and domain
# it's clear that it is an animal and eukaryote
def __str__(self):
return '{} ({})'.format(self.canonical_name, self.species)
serializers.py
from collections import OrderedDict
from rest_framework import serializers
from .models import Species
class SpeciesSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Animal
fields = ('url', 'id', 'canonical_name', 'species', 'genus',
'subfamily', 'family', 'order', 'class_name', 'phylum')
def to_representation(self, obj):
# call the parent method and get an OrderedDict
data = super(SpeciesSerializer, self).to_representation(obj)
# generate a list of the keys and replace the key 'class_name'
keys = list(data.keys())
keys.insert(keys.index('class_name'), 'class')
keys.remove('class_name')
# remove 'class_name' and assign its value to a new key 'class'
class_name = data.pop('class_name')
data.update({'class': class_name})
# create new OrderedDict with the order given by the keys
response = OrderedDict((k, data[k]) for k in keys)
return response
The method to_representation
helps us to manipulate the output. I have put some extra work here to get the taxonomic ranks in the desired order.
Thus for the red fox the output looks like this:
Red fox (Vulpes vulpes)
{
"url": "http://localhost:8000/animal/1",
"id": 1,
"canonical_name": "Red fox",
"species": "Vulpes vulpes",
"genus": "Vulpes",
"family": "Canidae",
"order": "Carnivora",
"class": "Mammalia",
"phylum": "Chordata"
}
It is a simplified example and in reality you'd have many more fields or possibly a model for every taxonomic rank, but somewhere you might come across the conflict between the reserved word class
and the taxonomic rank class.
I hope this can help other people too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With