You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django/RestFramework:如何从含外键的模型中获取数据

嘿,我来帮你理清楚在Django和DRF里怎么获取这类带外键的关联数据~ 结合你给出的Shops和Product模型,我分ORM查询和DRF序列化两个场景来说,都是日常开发里常用的方法:

一、Django ORM层面获取关联数据

不管是在视图还是脚本里,用ORM直接查关联数据很直观:

  • 正向查询:直接通过外键字段访问就行。比如拿到一个Product实例p,p.productsubcategory就能获取对应的子分类对象,p.shop拿到所属店铺;如果是店铺实例s,s.shopkeeper就能拿到店主。
    要是查多个对象,记得用select_related避免N+1查询问题,比如:
    # 一次性查出所有商品,以及对应的子分类和店铺
    products = Product.objects.select_related('productsubcategory', 'shop').all()
    
  • 反向查询:从关联的父模型查子模型,默认是模型名_set。比如要查某店铺的所有商品,用shop.product_set.all();查某店主的所有店铺用shopkeeper.shops_set.all()。
    嫌默认名字别扭的话,可以给外键加related_name改个直观的名字,比如在Product模型里:
    shop = models.ForeignKey(Shops, on_delete=models.CASCADE, related_name='products')
    
    之后就能用shop.products.all()来查店铺的商品了,舒服多了~
二、DRF序列化器返回关联数据

这部分是做API时最常用的,几种方式按需选:

  1. 默认主键返回:DRF默认会把外键字段序列化成对应对象的ID,比如Product序列化后shop字段就是店铺的ID,这种适合只需要关联ID的场景。
  2. 返回字符串表示:用StringRelatedField,前提是你给关联模型定义了__str__方法。比如给Shops加:
    def __str__(self):
        return self.name
    
    然后在ProductSerializer里:
    shop = serializers.StringRelatedField()
    
    这样序列化后shop字段就会返回店铺的名字。
  3. 嵌套序列化器(最常用):直接把关联对象的序列化器嵌套进来,返回完整的关联数据。比如先写好关联模型的序列化器,再嵌套:
    from rest_framework import serializers
    from .models import Shops, Product, ProductSubCategory, Shopkeeper
    
    # 先定义店主序列化器
    class ShopkeeperSerializer(serializers.ModelSerializer):
        class Meta:
            model = Shopkeeper
            fields = ['id', 'name'] # 按需选字段
    
    # 店铺序列化器,嵌套店主信息
    class ShopsSerializer(serializers.ModelSerializer):
        shopkeeper = ShopkeeperSerializer(read_only=True)
        # 如果要返回店铺的所有商品,加下面这行(记得给Product的外键加related_name='products')
        # products = ProductSerializer(many=True, read_only=True)
    
        class Meta:
            model = Shops
            fields = ['id', 'name', 'category', 'contactNumber', 'address', 'dateCreated', 'shopkeeper']
    
    # 商品子分类序列化器
    class ProductSubCategorySerializer(serializers.ModelSerializer):
        class Meta:
            model = ProductSubCategory
            fields = ['id', 'name']
    
    # 商品序列化器,嵌套子分类和店铺
    class ProductSerializer(serializers.ModelSerializer):
        productsubcategory = ProductSubCategorySerializer(read_only=True)
        shop = ShopsSerializer(read_only=True)
    
        class Meta:
            model = Product
            fields = ['id', 'productsubcategory', 'shop']
    
    然后在视图里用这个序列化器,记得配合select_related优化查询:
    from rest_framework import generics
    from .models import Product
    from .serializers import ProductSerializer
    
    class ProductList(generics.ListAPIView):
        queryset = Product.objects.select_related('productsubcategory', 'shop').all()
        serializer_class = ProductSerializer
    
  4. 自定义字段(SerializerMethodField):如果需要自定义关联数据的返回逻辑,用这个。比如在ProductSerializer里加个字段返回店铺的名字:
    shop_name = serializers.SerializerMethodField()
    
    def get_shop_name(self, obj):
        return obj.shop.name
    
    这样序列化后就会多一个shop_name字段,返回店铺名称。
小技巧:读写分离

如果需要在创建商品时传入店铺/子分类的ID,同时返回时显示详细信息,可以分开定义读写字段:

class ProductSerializer(serializers.ModelSerializer):
    # 只读字段,返回详细信息
    productsubcategory_detail = ProductSubCategorySerializer(source='productsubcategory', read_only=True)
    shop_detail = ShopsSerializer(source='shop', read_only=True)
    # 只写字段,接收ID
    productsubcategory = serializers.PrimaryKeyRelatedField(queryset=ProductSubCategory.objects.all())
    shop = serializers.PrimaryKeyRelatedField(queryset=Shops.objects.all())

    class Meta:
        model = Product
        fields = ['id', 'productsubcategory', 'productsubcategory_detail', 'shop', 'shop_detail']

内容的提问来源于stack exchange,提问作者Abid Mehmood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:44:19