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

Django ORM 无法通过 `ForeignKey` 自动关联,而是需要 **根据父模型中的某个字段(比如 ID)去查询子模型**。

Django ORM 无法通过 ForeignKey 自动关联,而是需要 根据父模型中的某个字段(比如 ID)去查询子模型

在 DRF 里,这种情况可以通过 SerializerMethodField自定义字段 来实现。


示例场景

假设:

class Parent(models.Model):id = models.AutoField(primary_key=True)name = models.CharField(max_length=100)# 没有外键,只有 parent_id 用来查询子模型class Child(models.Model):id = models.AutoField(primary_key=True)parent_id = models.IntegerField()  # 用 parent.id 关联content = models.CharField(max_length=200)

1️⃣ 使用 SerializerMethodField 获取子模型

from rest_framework import serializers
from .models import Parent, Childclass ChildSerializer(serializers.ModelSerializer):class Meta:model = Childfields = ("id", "content")class ParentSerializer(serializers.ModelSerializer):children = serializers.SerializerMethodField()class Meta:model = Parentfields = ("id", "name", "children")def get_children(self, obj):# 根据父模型的 id 查询子模型qs = Child.objects.filter(parent_id=obj.id)return ChildSerializer(qs, many=True).data

2️⃣ 在 View 中使用

from rest_framework import generics
from .models import Parent
from .serializers import ParentSerializerclass ParentListAPIView(generics.ListAPIView):queryset = Parent.objects.all()serializer_class = ParentSerializerclass ParentDetailAPIView(generics.RetrieveAPIView):queryset = Parent.objects.all()serializer_class = ParentSerializer

3️⃣ 优化性能

如果父模型很多,直接在 get_children 查询会导致 N+1 查询,可以提前把子模型查出来,然后传给 serializer:

class ParentListAPIView(generics.ListAPIView):serializer_class = ParentSerializerdef get_queryset(self):return Parent.objects.all()def list(self, request, *args, **kwargs):parents = self.get_queryset()parent_ids = [p.id for p in parents]children_qs = Child.objects.filter(parent_id__in=parent_ids)# 按 parent_id 分组children_map = {}for c in children_qs:children_map.setdefault(c.parent_id, []).append(c)# 把 children_map 传给 serializer contextserializer = self.get_serializer(parents, many=True, context={"children_map": children_map})return Response(serializer.data)

然后在 serializer 里:

def get_children(self, obj):children_map = self.context.get("children_map", {})qs = children_map.get(obj.id, [])return ChildSerializer(qs, many=True).data

这样只会做 两条 SQL 查询,避免 N+1。


✅ 总结

  • 没有外键关系 → 用 SerializerMethodField 或自定义字段查询
  • N+1 查询问题 → 可以提前批量查询子模型并用 context 传递
  • 适用于一对多、多对多但没有数据库约束的场景

如果你需要,我可以帮你写一个 通用方法,输入父模型 queryset 和子模型 queryset,自动生成嵌套返回的数据,完全不依赖外键。你希望我直接写吗?

http://www.dtcms.com/a/442142.html

相关文章:

  • 吉林省建设厅信息网站网站建设的评价
  • 分布式专题——26.5 一台新机器进行Web页面请求的历程
  • 怎么让别人看到自己做的网站万维网网站301重定向怎么做
  • css样式学习记录
  • 网站服务器关闭网站数据库地址是什么
  • 每日一个C语言知识:C程序结构
  • Amazon RDS:云端数据库管理的革新之路
  • wordpress登录可见站内seo是什么意思
  • STM32简单的串口Bootloader入门
  • 360网站怎么做2核4g做网站
  • 从 “手工作坊” 到 “智能工厂”:2025 年 AI 原生应用重构内容创作产业
  • 做网站平台难在哪里网页翻译不见了
  • Flutter技术栈深度解析:从架构设计到性能优化
  • 学做湘菜的视频网站中国建设企业银行登录网站
  • 【Python进阶】网络爬虫核心技能-第三方IP服务
  • CAS密钥管理系统在汽车行业的核心密钥管理实践——构建智能网联汽车的可信安全底座
  • 宝塔面板登录地址和账密都忘了怎么解决
  • 廊坊大城网站建设义乌创源网站建设
  • Spring-AI 接入(本地大模型 deepseek + 阿里云百炼 + 硅基流动)
  • 华为OD机试C卷 - 分苹果 - 二进制 - (Java C++ JavaScript Python)
  • 国内好的seo网站网站建设课程的感受
  • 用 Gradle 配置 Flink 从开发到打包的一条龙实践
  • gRPC从0到1系列【17】
  • 浅谈内存DDR——DDR4性能优化技术
  • 静态网页模板网站电商运营培训班
  • mysqldump导入备份数据到阿里云RDS会报错吗
  • QT肝8天16--加载动态菜单
  • Spring Boot整合缓存——Redis缓存!超详细!
  • 湘潭做网站品牌磐石网络wordpress 柚子皮
  • 前端实战开发(二):React + Canvas 网络拓扑图开发:6 大核心问题与完整解决方案