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

如何在Django REST中通过关联表外键过滤模型对象(餐厅API场景)

嘿,针对你在Django REST框架里通过外键过滤模型对象的需求,结合你给出的Table和Order模型,我整理了几种实用的方法,你可以按需选用:

方法1:使用django-filter的FilterSet(推荐,功能灵活)

这是DRF里最常用的过滤方案,支持复杂的过滤逻辑,步骤如下:

  1. 先安装依赖(如果还没装的话):
pip install django-filter
  1. 在项目的settings.py里配置:
INSTALLED_APPS = [
    # 其他app...
    'django_filters',
]

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
        # 可以搭配其他过滤后端比如SearchFilter
    ]
}
  1. 定义过滤规则的FilterSet类(比如在filters.py里):
import django_filters
from .models import Order

class OrderFilter(django_filters.FilterSet):
    # 直接根据外键table_id过滤订单
    table_id = django_filters.NumberFilter(field_name='table_id')
    # 过滤关联的Table表中is_free为指定值的订单(比如找所有在空闲桌子的订单)
    table_is_free = django_filters.BooleanFilter(field_name='table_id__is_free')
    # 还可以加更多过滤规则,比如按桌子名称模糊匹配
    table_name = django_filters.CharFilter(field_name='table_id__name', lookup_expr='icontains')

    class Meta:
        model = Order
        fields = ['table_id', 'table_is_free', 'table_name']
  1. 在视图中使用这个FilterSet:
from rest_framework import generics
from .models import Order
from .serializers import OrderSerializer
from .filters import OrderFilter

class OrderListView(generics.ListAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    filterset_class = OrderFilter

现在你就可以通过URL参数过滤了,比如:

  • 找table_id为1的订单:/api/orders/?table_id=1
  • 找所有在空闲桌子的订单:/api/orders/?table_is_free=True
  • 找桌子名称包含"VIP"的订单:/api/orders/?table_name=VIP
方法2:视图中手动过滤(适合简单场景)

如果你的过滤逻辑很简单,不想引入额外依赖,可以直接在视图的get_queryset方法里处理:

from rest_framework import generics
from .models import Order
from .serializers import OrderSerializer

class OrderListView(generics.ListAPIView):
    serializer_class = OrderSerializer

    def get_queryset(self):
        queryset = Order.objects.all()
        # 获取URL参数里的table_id
        table_id = self.request.query_params.get('table_id')
        if table_id:
            queryset = queryset.filter(table_id=table_id)
        
        # 过滤关联表的is_free字段
        table_is_free = self.request.query_params.get('table_is_free')
        if table_is_free is not None:
            # 注意这里的语法:外键字段__关联表字段
            queryset = queryset.filter(table_id__is_free=table_is_free)
        
        return queryset

同样可以用/api/orders/?table_id=2或者/api/orders/?table_is_free=False来过滤。

方法3:使用DRF的SearchFilter(针对模糊搜索关联字段)

如果需要模糊搜索外键关联表的字段(比如根据桌子名称搜索订单),可以用DRF自带的SearchFilter:

from rest_framework import generics, filters
from .models import Order
from .serializers import OrderSerializer

class OrderListView(generics.ListAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    filter_backends = [filters.SearchFilter]
    # 指定要搜索的关联字段:table_id是外键,__name是关联Table表的name字段
    search_fields = ['table_id__name']

请求时用/api/orders/?search=包间就能找到所有对应桌子名称包含"包间"的订单。

小提示

过滤关联表字段时,Django ORM的语法是外键字段名__关联表字段名,比如table_id__is_free、table_id__name,这个语法在所有DRF过滤方案里都适用哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:20:32