Фильтр по другим полям 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