Python 使用保留字";“类”;作为Django和Django REST框架中的字段名 问题的描述

Python 使用保留字";“类”;作为Django和Django REST框架中的字段名 问题的描述,python,django,python-3.x,django-rest-framework,bioinformatics,Python,Django,Python 3.x,Django Rest Framework,Bioinformatics,分类学是一门根据共同特征定义和命名生物群体的科学。生物被分成分类单元(单数:分类单元),这些分类单元被赋予一个分类等级。现代使用的主要等级是领域、王国、门、纲、目、科、属和种。 更多关于维基百科的信息 按照Wikipedia中文章分类等级中的红狐的例子,我需要创建一个JSON输出,如下所示: { "species": "vulpes", "genus": "Vulpes", "family": "Canidae", "order": "Carnivora",

分类学是一门根据共同特征定义和命名生物群体的科学。生物被分成分类单元(单数:分类单元),这些分类单元被赋予一个分类等级。现代使用的主要等级是领域、王国、门、纲、目、科、属和种。 更多关于维基百科的信息

按照Wikipedia中文章分类等级中的红狐的例子,我需要创建一个JSON输出,如下所示:

{
    "species": "vulpes",
    "genus": "Vulpes",
    "family": "Canidae",
    "order": "Carnivora",
    "class": "Mammalia",
    "phylum": "Chordata",
    "kingdom": "Animalia",
    "domain": "Eukarya"
}
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
问题: 是否有任何可能的方法来解决此问题并生成所需的输出?
如果没有,解决这个问题的最佳实践是什么?

生物信息学领域的其他软件开发人员可能对这个问题的解决方案感兴趣,因此我在这里发布了我的方法,正如Alasdair所建议的

为了简单起见,我们的目标是为一个活着的物种创建一个模型,比如说一个动物,并使用Django REST框架创建一个端点,表示正确的分类等级

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)
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
序列化程序.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)
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
方法
to_表示法
帮助我们操作输出。我在这里做了一些额外的工作,以便按照所需的顺序获得分类等级

因此,对于系统,输出如下所示:

{
    "species": "vulpes",
    "genus": "Vulpes",
    "family": "Canidae",
    "order": "Carnivora",
    "class": "Mammalia",
    "phylum": "Chordata",
    "kingdom": "Animalia",
    "domain": "Eukarya"
}
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
红狐

这是一个简化的示例,实际上,对于每个分类等级,您可能会有更多的字段或可能有一个模型,但在某些地方,您可能会遇到保留字
class
和分类等级之间的冲突。

我希望这也能帮助其他人。

你可以像下面这样做

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")
正如下面的答案所解释的


您可以在重载版本的
get\u 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

有关如何在django rest框架中重命名字段的信息,请参阅。您可以在Django模型字段中使用类似于
species\u class
klass
的内容。@Alasdair非常感谢您,朋友!借助序列化程序方法
到_表示
我找到了一个解决方案。我现在调用的model字段
class\u name
,这并不麻烦,因为客户机只关心输出。请你加几行作为答案,这样我就可以投票/接受了。很高兴这有帮助。如果您添加自己的答案可能会更好,因为您可以展示您为使其工作所做的实际工作。谢谢!我也要试试这个方法。绝对是最干净的方法