Using the reserved word "class" as a field name in Django and Django REST Framework

Description of the problem

Taxonomy is the science of defining and designating groups of biological organisms based on common characteristics. Organisms are grouped into taxa (single: taxon), and these groups receive a taxonomic rank. The main rows in modern use are the domain, kingdom, type, class, order, family, gender and species. Learn more about Taxonomy and Taxonomic Ranks on Wikipedia.

Following the example of red fox in the Wikipedia article Taxonomic Rank , I need to create a JSON output as follows:

{ "species": "vulpes", "genus": "Vulpes", "family": "Canidae", "order": "Carnivora", " class ": "Mammalia", "phylum": "Chordata", "kingdom": "Animalia", "domain": "Eukarya" } 

Since the Django REST Framework creates keys based on field names, the problem arises with the taxonomic rank class (bold in the example), because it is a reserved word in Python and cannot be used as a variable name.

What i tried

The model class created in Django will 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 

Question

Is there any possible way to solve this problem and create the desired result? If not, what is the best practice to solve this problem?

+9
source share
4 answers

You can do it as 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 below, answer

fooobar.com/questions/1273837 / ...

+4
source

Other bioinformatics software developers may be interested in solving this problem, so I post here my approach proposed by Alasdair .

The goal is to create a model for living species, for simplicity, say, an animal, and create an endpoint with the 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 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 to_representation method helps us manage the result. I added extra work to get taxonomic ranks in the desired order.

Thus, for red fox, the result is as follows:

Red fox (vulva vulva)

 { "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" } 

This is a simplified example, and in fact you will have many fields, or perhaps a model for each taxonomic rank, but somewhere you might run into a conflict between the reserved word class and the taxonomic rank of class .
Hope this helps other people as well.

+5
source

You can rename the field in the overloaded version of get_fields()

 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 
+2
source

can do this in a simple way by adding verbose_name to the field in models

models.py

 class Species(models.Model): ... # enter all other fields related to species class_name = models.CharField(verbose_name=_('Class')) 

serializers.py

 from rest_framework import serializers class SpeciesSerializer(serializers.ModelSerializer): class Meta: model = Species fields = ('id', 'species', 'family', 'class_name', 'genus') 
0
source

Source: https://habr.com/ru/post/1273836/


All Articles