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

如何在Django REST Framework中根据关联模型数据过滤主模型并返回匹配结果

Hey there! Let's work through how to filter your MainModel records based on the related ModelAdditionalData_1 and ModelAdditionalData_2 fields using those query parameters. Here's a step-by-step solution:

First, Fix a Tiny Model Typo

I spotted a small mistake in your related models: the OneToOneField references Model, but your main model is named MainModel. Plus, there's a duplicate models. prefix on the DecimalField definitions. Correct those first to avoid errors:

class ModelAdditionalData_1(TimeStampedModel):
    model_id = models.OneToOneField(
        MainModel,  # Changed from "Model" to "MainModel"
        verbose_name=_('related model'), 
        on_delete=models.CASCADE,
        related_name='model_water_flow_data1', 
        related_query_name='model_water_flow_data1'
    )
    model_param_1 = models.DecimalField(_("model_param_1"), max_digits=8)  # Fixed duplicate "models."

class ModelAdditionalData_2(TimeStampedModel):
    model_id = models.OneToOneField(
        MainModel,  # Changed from "Model" to "MainModel"
        verbose_name=_('related model'), 
        on_delete=models.CASCADE,
        related_name='model_water_flow_data2', 
        related_query_name='model_water_flow_data2'
    )
    model_param_2 = models.DecimalField(_("model_param_2"), max_digits=8)  # Fixed duplicate "models."

Update Your View to Handle Filtering

Instead of handling filtering directly in the list method, override the get_queryset method (this follows DRF best practices). We'll use Django's double-underscore lookup to filter across the one-to-one relationships:

from decimal import Decimal, InvalidOperation

DETAIL_FILTER_PARAMETERS = [
    openapi.Parameter(
        'model_param_1', openapi.IN_QUERY, type=openapi.TYPE_STRING, format=openapi.FORMAT_DECIMAL
    ),
    openapi.Parameter(
        'model_param_2', openapi.IN_QUERY, type=openapi.TYPE_STRING, format=openapi.FORMAT_DECIMAL
    )
]

@method_decorator(name='list', decorator=swagger_auto_schema(
    manual_parameters=DETAIL_FILTER_PARAMETERS))
class ModelsViewSet(ReadOnlyModelViewSet):
    serializer_class = ModelsSerializer
    queryset = MainModel.objects.all()

    def get_queryset(self):
        # Start with the base queryset
        queryset = super().get_queryset()
        
        # Extract query parameters from the request
        param1 = self.request.query_params.get('model_param_1')
        param2 = self.request.query_params.get('model_param_2')

        # Build dynamic filter dictionary
        filters = {}
        
        # Handle model_param_1: validate and add to filters
        if param1 is not None:
            try:
                # Convert string to Decimal to match the field type
                param1_decimal = Decimal(param1)
                filters['model_water_flow_data1__model_param_1'] = param1_decimal
            except InvalidOperation:
                # Optional: Return empty set or raise a 400 error for invalid input
                return MainModel.objects.none()
        
        # Handle model_param_2 similarly
        if param2 is not None:
            try:
                param2_decimal = Decimal(param2)
                filters['model_water_flow_data2__model_param_2'] = param2_decimal
            except InvalidOperation:
                return MainModel.objects.none()
        
        # Apply filters if any are set
        if filters:
            queryset = queryset.filter(**filters)
        
        return queryset

How This Works

  • The related_name values (model_water_flow_data1 and model_water_flow_data2) let us traverse from MainModel to its related data using the double-underscore syntax (model_water_flow_data1__model_param_1).
  • We validate incoming string parameters to convert them to Decimal (matching your model field type) to avoid type mismatches.
  • Filters are applied dynamically: if only one parameter is provided, it filters on just that field; if both are provided, it returns records that match both conditions.

If you want the response to include the related ModelAdditionalData fields, update your serializer to nest them:

from rest_framework import serializers

class ModelAdditionalData1Serializer(serializers.ModelSerializer):
    class Meta:
        model = ModelAdditionalData_1
        fields = ['model_param_1']

class ModelAdditionalData2Serializer(serializers.ModelSerializer):
    class Meta:
        model = ModelAdditionalData_2
        fields = ['model_param_2']

class ModelsSerializer(serializers.ModelSerializer):
    model_water_flow_data1 = ModelAdditionalData1Serializer()
    model_water_flow_data2 = ModelAdditionalData2Serializer()

    class Meta:
        model = MainModel
        fields = ['id', 'model_name', 'model_price', 'model_water_flow_data1', 'model_water_flow_data2']

Test Your Filter

Run your server and use the curl command you provided:

curl -X GET "http://localhost:8000/api/v1/models/?model_param_1=1&model_param_2=2" -H "accept: application/json"

This will return only MainModel records where the related ModelAdditionalData_1.model_param_1 equals 1 and ModelAdditionalData_2.model_param_2 equals 2.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 10:52:30