当前位置: 首页 > article >正文

Django一分钟:DRF模型序列化器处理关联关系的示例与注意事项

DRF的ModelSerializer序列化器与Django的Model模型紧密映射,本文将通过简单的示例介绍几种处理关联关系的方法。

1. 创建模型和初始数据

创建模型

from django.db import models

class Product(models.Model):
    product_name = models.CharField(max_length=255)
    quantity = models.IntegerField()

class Component(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='components')
    component_name = models.CharField(max_length=255)
    code = models.CharField(max_length=255)
    quantity = models.IntegerField()

    class Meta:
        ordering = ['product']

    def __str__(self):
        return f'{self.code}-{self.component_name}'

创建数据

>>> from api.models import Product, Component
>>> p1 = Product.objects.create(product_name="盖子", quantity=30)
>>> Component.objects.create(product=p1, component_name='纤维板', code='XYB', quantity=5)
>>> Component.objects.create(product=p1, component_name='螺丝', code='LS', quantity=10)
>>> Component.objects.create(product=p1, component_name='密封条', code='MFT', quantity=20)

2. 字符串关系字段

使用StringRelatedField

from rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.ModelSerializer):
    components = serializers.StringRelatedField(many=True)

    class Meta:
        model = Product
        fields = ['product_name', 'quantity', 'components']

执行查询和序列化

>>> from api.models import Product
>>> p1 = Product.objects.prefetch_related('components').get(pk=1)
>>> from api.serializers import ProductSerializer
>>> ps = ProductSerializer(p1)
>>> ps.data
# {'product_name': '盖子', 'quantity': 30, 'components': ['XYB-纤维板', 'LS-螺丝', 'MFT-密封条']}

效果如下:

{
    'product_name': '盖子', 
    'quantity': 30, 
    'components': [
        'XYB-纤维板', 
        'LS-螺丝', 
        'MFT-密封条'
    ]
}

注意观察获取查询集的代码:Product.objects.prefetch_related('components').get(pk=1)不难发现我们使用了prefetch_related来获取查询集,如果一次查询大量的Product,不使用prefetch_related将会导致严重的性能问题(N+1问题)。DRF的序列化器不会为你自动优化。当然我们的示例中影响不大,因为只获取了一个查询集。

3. 主键关系字段

使用PrimaryKeyRelatedField

from rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.ModelSerializer):
    components =  serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Product
        fields = ['product_name', 'quantity', 'components']

效果如下:

{
    'product_name': '盖子', 
    'quantity': 30, 
    'components': [
        1, 
        2, 
        3
    ]
}

4. 指定关系字段

使用SlugRelatedField可以指定字段来表示关联关系:

from rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.ModelSerializer):
    components =  serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='code'
     )

    class Meta:
        model = Product
        fields = ['product_name', 'quantity', 'components']

效果如下:

{
    'product_name': '盖子', 
    'quantity': 30, 
    'components': [
        'XYB', 
        'LS', 
        'MFT'
    ]
}

5. 嵌套序列化器

from rest_framework import serializers
from .models import Product, Component

class ComponentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Component
        fields = ['component_name', 'code', 'quantity']

class ProductSerializer(serializers.ModelSerializer):
    components =  ComponentSerializer(many=True, read_only=True)

    class Meta:
        model = Product
        fields = ['product_name', 'quantity', 'components']

效果如下:

{
    "product_name": "盖子",
    "quantity": 30,
    "components": [
        {
            "component_name": "纤维板",
            "code": "XYB",
            "quantity": 5
        },
        {
            "component_name": "螺丝",
            "code": "LS",
            "quantity": 10
        },
        {
            "component_name": "密封条",
            "code": "MFT",
            "quantity": 20
        }
    ]
}

6. 可写嵌套

默认上面创建的嵌套序列化器是只读的,可写嵌套需要实现updatecreate两者或其一:

from rest_framework import serializers
from .models import Product, Component

class ComponentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Component
        fields = ['component_name', 'code', 'quantity']

class ProductSerializer(serializers.ModelSerializer):
    components =  ComponentSerializer(many=True)

    class Meta:
        model = Product
        fields = ['product_name', 'quantity', 'components']

    def create(self, validated_data):
        components_data = validated_data.pop('components')
        product = Product.objects.create(**validated_data)
        for component_data in components_data:
            Component.objects.create(product=product, **component_data)
        return product

可以使用此序列化器创建实例:

>>> data = {
    "product_name": "电机",
    "quantity": 1,
    "components": [
        {
            "component_name": "铝型材",
            "code": "LXC",
            "quantity": 5
        },
        {
            "component_name": "螺栓",
            "code": "LSHUN",
            "quantity": 10
        },
    ]
}
>>> from api.serializers import ProductSerializer
>>> s = ProductSerializer(data=data)
>>> s.is_valid()
# True
>>> s.save()
# <Product: Product object (2)>

7. 总结注意事项

  1. 关联关系注意使用prefetch_related获取查询集。
  2. 可写嵌套序列化器必须自己实现create方法update方法两者或其一。

http://www.kler.cn/news/331119.html

相关文章:

  • 高校实训产品:动漫和游戏场景AI实训平台建设方案
  • 《Spring Boot应用进阶:打造优雅的错误处理机制与全局异常拦截器》
  • 如何在 Flutter 中实现可拖动的底部弹出框
  • 滚雪球学MySQL[7.2讲]:MySQL安全策略详解:数据加密与SQL注入防护
  • 网安学习(js漏洞挖掘)
  • 登录功能开发 P167重点
  • 每日一练:零钱兑换
  • ScatterAdd算子实现简介
  • 【Android】【bug】ImageView设置scaleType不生效的问题
  • 毕业设计选题:基于ssm+vue+uniapp的教学辅助小程序
  • 十进制转十六进制 ← Python字符串
  • 【Spring】Spring Boot项目创建和目录介绍
  • 计算机毕业设计 基于Python的无人超市管理系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档
  • C#/.NET/.NET Core技术前沿周刊 | 第 7 期(2024年9.23-9.30)
  • Hive数仓操作(十)
  • MySQL-MySQL访问
  • Spring Boot实现IT知识分享社区
  • 初识 C 语言(2)
  • CF2018C Tree Pruning 题解
  • C--编译和链接见解