如何在Django REST Framework中实现一对多嵌套关联?附模型与预期输出
没问题,我来帮你一步步实现Django REST Framework里的一对多嵌套关联,刚好匹配你想要的输出格式。先从模型定义开始,再到序列化器、视图,最后验证效果。
1. 完善模型定义(models.py)
首先得确保你的Product和Tax模型是一对多关系(一个商品对应多个税项),所以在Tax模型里要添加外键关联Product,并且设置related_name为tax_details,这样后续序列化时能直接通过这个名称获取关联的税项:
from django.db import models class Product(models.Model): product_name = models.CharField(max_length=100) description = models.TextField() sales = models.DecimalField(max_digits=10, decimal_places=2) cost = models.DecimalField(max_digits=10, decimal_places=2) def __str__(self): return self.product_name class Tax(models.Model): product = models.ForeignKey( Product, on_delete=models.CASCADE, related_name='tax_details' # 这个名称要和你预期输出里的字段名一致 ) tax_name = models.CharField(max_length=50) percentage = models.DecimalField(max_digits=5, decimal_places=2) def __str__(self): return f"{self.tax_name} - {self.percentage}%"
2. 编写嵌套序列化器(serializers.py)
接下来要写序列化器,这里需要嵌套序列化:先定义TaxSerializer处理单个税项的序列化,然后在ProductSerializer里用它来序列化关联的多个税项集合。另外你预期里的tax_name是API URL,所以我们用HyperlinkedIdentityField来生成对应的详情URL:
from rest_framework import serializers from .models import Product, Tax class TaxSerializer(serializers.ModelSerializer): # 生成税项的详情URL,对应你预期里的tax_name字段 tax_name = serializers.HyperlinkedIdentityField( view_name='tax-detail', # 这个要和你urls里定义的税项详情视图名称一致 lookup_field='pk' ) class Meta: model = Tax fields = ['id', 'tax_name', 'percentage'] class ProductSerializer(serializers.ModelSerializer): # 嵌套序列化关联的税项,many=True表示是多个对象,read_only=True表示只用于序列化输出 tax_details = TaxSerializer(many=True, read_only=True) class Meta: model = Product fields = ['id', 'product_name', 'description', 'sales', 'cost', 'tax_details']
3. 配置视图和路由
视图部分(views.py)
用ModelViewSet来快速实现商品的列表、详情接口,税项的接口也可以用同样的方式:
from rest_framework import viewsets from .models import Product, Tax from .serializers import ProductSerializer, TaxSerializer class ProductViewSet(viewsets.ModelViewSet): queryset = Product.objects.all() serializer_class = ProductSerializer class TaxViewSet(viewsets.ModelViewSet): queryset = Tax.objects.all() serializer_class = TaxSerializer
路由部分(urls.py)
配置路由,注意要给税项的详情视图设置名称tax-detail,和序列化器里的view_name对应:
from django.urls import path, include from rest_framework.routers import DefaultRouter from .views import ProductViewSet, TaxViewSet router = DefaultRouter() router.register(r'products', ProductViewSet) router.register(r'tax', TaxViewSet, basename='tax') # basename用来生成视图名称,这里会生成tax-detail urlpatterns = [ path('', include(router.urls)), ]
4. 验证效果
现在你可以创建一些测试数据:先创建Product,再创建关联它的Tax记录,然后访问http://127.0.0.1:8000/products/1/(假设商品id是1),就能得到你想要的输出格式:
{ "id": 1, "product_name": "Rice", "description": "expired on 13-04-2018", "sales": "55.00", "cost": "55.00", "tax_details": [ { "id": 1, "tax_name": "http://127.0.0.1:8000/tax/1/", "percentage": "10.00" }, { "id": 2, "tax_name": "http://127.0.0.1:8000/tax/3/", "percentage": "20.00" } ] }
关键注意点
related_name必须和你预期输出里的嵌套字段名(tax_details)一致,这样DRF才能找到关联的税项数据。- 嵌套序列化器的
many=True是必须的,因为一个商品对应多个税项,是集合类型。 HyperlinkedIdentityField的view_name要和路由里生成的详情视图名称完全匹配,否则会生成不了URL。
内容的提问来源于stack exchange,提问作者Sudharsan Venkatraj
相关产品推荐
相关产品推荐

