Django Rest Framework - 将序列化器字段映射到数据库列名

Posted

技术标签:

【中文标题】Django Rest Framework - 将序列化器字段映射到数据库列名【英文标题】:Django Rest Framework - mapping serializers fields to a database column name 【发布时间】:2015-12-26 03:36:28 【问题描述】:

我正在处理 Django Rest Framework 项目,我的视图的通用响应不是应用客户端所期望的。

应用程序客户端期望相关模型的文件以它们在数据库中的形式出现。给出的示例:模型 City 具有 Country 模型的外键,由 country_id 列表示。

是否有任何选项可以将序列化程序的默认字段“映射”到自定义字段?我检查了 Django Rest Framework 文档,但我只找到了“serializer_field_mapping”,但我不知道它是否符合我的要求,也不知道如何使用它。

不知何故,我得到了一个接近的方法,但仅在获取数据的情况下——创建/更新引发了一些我不知道如何管理的错误。 :(

下面我附上我的 models.py 文件,以及实际输出和所需的输出。此外,如果可能的话,如果存在与数据库列 field_id 名称相结合的国家/地区相关数据,我想检索。

提前致谢,

models.py

from django.db import models
from django.contrib.postgres.fields import ArrayField


class Country(models.Model):

    name = models.CharField(max_length=150, unique=True, blank=False)

    class Meta:
        db_table = 'countries'


class Region(models.Model):

    name = models.CharField(max_length=150, unique=True, blank=False)
    code = models.CharField(max_length=150, blank=True)

    class Meta:
        db_table = 'regions'


class City(models.Model):

    country = models.ForeignKey(Country)
    region = models.ForeignKey(Region, null=True, blank=True, default=None)
    name = models.CharField(max_length=150, unique=True, blank=False)
    postal_codes = ArrayField(models.CharField(max_length=12, blank=True), null=True, blank=True, default=None)

    def __str__(self):
        if not self.region:
            return '%s (%s)' % (self.name, self.country.name)
        return '%s, %s (%s)' % (self.name, self.region.name, self.country.name)

    class Meta:
        db_table = 'cities'

实际输出:

[
  
    "id": 1,
    "name": "San Francisco",
    "postal_codes": null,
    "country": 1,
    "region": 1
  ,
  
    "id": 2,
    "name": "Palo Alto",
    "postal_codes": null,
    "country": 1,
    "region": 1
  ,
  
    "id": 3,
    "name": "New York City",
    "postal_codes": null,
    "country": 1,
    "region": 2
  ,
  
    "id": 4,
    "name": "London",
    "postal_codes": null,
    "country": 2,
    "region": null
  
]

所需的输出:

[
  
    "id": 1,
    "country_id": 1,
    "region_id": 1,
    "name": "San Francisco",
    "postal_codes": null
  ,
  
    "id": 2,
    "country_id": 1,
    "region_id": 1,
    "name": "Palo Alto",
    "postal_codes": null
  ,
  
    "id": 3,
    "country_id": 1,
    "region_id": 2,
    "name": "New York City",
    "postal_codes": null
  ,
  
    "id": 4,
    "country_id": 2,
    "region_id": null,
    "name": "London",
    "postal_codes": null
  
]

【问题讨论】:

【参考方案1】:

您可以使用序列化程序上字段的source 参数来实现此目的。例如:

from rest_framework import serializers

from .models import City


class CitySerializer(serializers.ModelSerializer):
    country_id = serializers.IntegerField(source='country')
    region_id = serializers.IntegerField(source='region')

    class Meta:
        model = City
        fields = ('id', 'country_id', 'region_id', 'name', 'postal_codes')

编辑: 正如 Yaroslav 指出的那样,以这种方式执行此操作时,您不需要包含 source。但是请注意,仅在fields 列表中包含country_idregion_id 是不够的。您仍然需要在序列化程序上指定字段,例如country_id = serializers.IntegerField(),并将其包含在fields 中。

【讨论】:

看来 OP 不需要 source,因为他想在 country_idregion_id 中拥有 id。 当然可以,但它不会提供一些 django rest 框架默认验证。 POST /cities/ name: San José, country_id: 999999 将提供一个带有 IntegrityError at /cities/ insert or update on table "cities" violates foreign key constraint "cities_country_id_2cc874aa51973821_fk_countries_id" DETAIL: Key (country_id)=(999) is not present in table "countries".html 数据库表约束也是如此。 @JordiMarínValle 使用PrimaryKeyRelatedField 而不是IntegerField 谢谢大家。终于明白了!【参考方案2】:

谢谢大家。最后我明白了。请参见下面的代码。由于无法在答案评论中添加大量行,因此我回答了我的问题。

serializers.py

from rest_framework import serializers
from .models import Country, Region, City


class CountrySerializer(serializers.ModelSerializer):

    class Meta:
        model = Country
        fields = ('id', 'name')


class RegionSerializer(serializers.ModelSerializer):

    class Meta:
        model = Region
        fields = ('id', 'name', 'code')


class CitySerializer(serializers.ModelSerializer):

    country_id = serializers.PrimaryKeyRelatedField(
        queryset=Country.objects.all(),
        required=True,
        source='country',
    )
    region_id = serializers.PrimaryKeyRelatedField(
        queryset=Region.objects.all(),
        allow_null=True,
        required=False,
        source='region',
    )

    country = CountrySerializer(
        read_only=False,
        required=False,
    )
    region = RegionSerializer(
        required=False,
        allow_null=True,
        read_only=True,
    )

    class Meta:
        model = City
        fields = (
            'id',
            'country', 'region',
            'name', 'postal_codes',
            'country_id', 'region_id',
        )

【讨论】:

以上是关于Django Rest Framework - 将序列化器字段映射到数据库列名的主要内容,如果未能解决你的问题,请参考以下文章

django-rest-framework:如何序列化已经包含 JSON 的字段?

python 将django密码验证器与django rest framework validate_password集成

django-rest-framework 是不是提供管理站点来管理模型?

如何仅使用 django 作为后端并使用 django-rest-framework 发布

在 django-rest-framework 中插入 django-allauth 作为端点

Django rest framework 之分页