Фильтр по другим полям SlugRelatedField в Django Rest Framework

У меня есть модель с несколькими отношениями ForeignKey и я хочу создать API POST, который позволит мне публиковать их полные имена, а не id. Это кажется работой для SlugRelatedField, однако это не позволяет мне предоставить набор запросов, который фильтруется на основе других полей в JSON сообщении. Проблема в том, что поля должны быть отфильтрованы на основе других полей в JSON-запросе.

class GenericReportSerializer(serializers.ModelSerializer):
    """
    GenericReportSerializer for POST.
    """
    organization = serializers.SlugRelatedField(slug_field='name', queryset=models.Organization.objects.all())
    subdivision = serializers.SlugRelatedField(slug_field='name', queryset=models.Subdivision.objects.all())  # queryset needs to be filtered by organization
    prediction_model = serializers.SlugRelatedField(slug_field='name', queryset=models.PredictionModel.objects.all())  # queryset needs to be filtered by both organization and subdivision

    class Meta:
        model = models.GenericReport
        fields = '__all__'  # use all fields

Организации уникальны по имени, поэтому SlugField подходит. Однако subdivisions не имеют уникальных имен и должны быть отфильтрованы organization, а prediction_model должны быть отфильтрованы и organization, и subdivision. Я не нашел удобного способа соединять фильтры в цепочку в Django Rest Framework, а расширение класса SlugRelatedField не дает мне доступа ко всей структуре данных. Есть ли хороший способ решить эту задачу?

Вы можете создать сериализатор для каждой модели и затем построить отношение от GenericReport к organization к subdivision к prediction_model.

Я предполагаю, что они связаны с помощью ForeignKey или ManyToMany Relationships.

class PredictionModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.PredictionModel
        fields = '__all__'

class SubdivisionSerializer(serializers.ModelSerializer):
    # TODO: adjust name prediction_model to the name of the related field
    prediction_model = PredictionModelSerializer(read_only=True, many=True)

    class Meta:
        model = models.Subdivision
        fields = '__all__'

class OrganizationSerializer(serializers.ModelSerializer):
    # TODO: adjust name subdivision to the name of the related field
    subdivision = SubdivisionSerializer(read_only=True, many=True)

    class Meta:
        model = models.Organization
        fields = '__all__'

class GenericReportSerializer(serializers.ModelSerializer):
    name = OrganizationSerializer(read_only=True, many=True)

    class Meta:
        model = models.GenericReport
        fields = '__all__'  # use all fields

Если вы сериализуете GenericReport, вы получите вложенный json POST ответ со всей сопутствующей информацией, и вы можете довольно гибко менять поля поведения и т.д.

Вы можете настроить slug Related, вы просто передаете запрос в контексте, и вы можете получить доступ к request_data, а затем вы можете фильтровать

class SubDivisionSlugRelatedField(serializers.SlugRelatedField):
    def get_queryset(self):
        organisation_name = self.context['request'].data.get('organization')
        return SubDivision.objects.filter(organisation__name=organisation_name)

class PredictionModelSlugRelatedField(serializers.SlugRelatedField):
    def get_queryset(self):
        organisation_name = self.context['request'].data.get('organization')
        subdivision_name = self.context['request'].data.get('subdivision')
        return PredictionModel.objects.filter(organisation__name=organisation_name,
        subdivision__name=subdivision_name)

class ReportSerializer(serializers.ModelSerializer):
    organization = serializers.SlugRelatedField(slug_field='name', queryset=Organisation.objects.all())
    subdivision = SubDivisionSlugRelatedField(slug_field='name', queryset=SubDivision.objects.all())  # queryset needs to be filtered by organization
    prediction_model = PredictionModelSlugRelatedField(slug_field='name', queryset=PredictionModel.objects.all())  # queryset needs to be filtered by both organization and subdivision

    class Meta:
        model = Report
        fields = '__all__'  # use all field
Вернуться на верх