DRF, вложенная через фильтрацию сериализации модели

Каждая из моих моделей наследуется от базовой модели, которая содержит поле publishing_status , которое помогает мне контролировать, будет ли объект включен в возвращаемые данные.

class BaseModel(models.Model):
    class PublishingStatus(models.TextChoices):
        ACCEPTED = 'accepted', 'Accepted'
        REJECTED = 'rejected', 'Rejected'

    publishing_status = models.CharField(
        max_length=9,
        choices=PublishingStatus.choices,
        default=PublishingStatus.DRAFT,
        help_text="Publishing status represents the state of the object. By default it is 'draft'"
    )

    class Meta:
        abstract = True

Вот две модели Word и Homonym они обе наследуют от BaseModel:

class Word(BaseModel):
    definition = models.CharField(max_length=255)
    homonyms = models.ManyToManyField('self', through='Homonym', through_fields=('homonym', 'word'))


class Homonym(BaseModel):
    homonym = models.ForeignKey(Word, on_delete=models.CASCADE)
    word = models.ForeignKey(Word, on_delete=models.CASCADE)

Омонимы, по сути, тоже являются словами, поэтому здесь у меня есть самореференция, но через модель Homonym, так что я могу контролировать эти отношения, чтобы они были публичными или нет для моего сайта.

Затем следуйте за сериализаторами и, вероятно, решение должно быть передано сюда:

class HomonymSerializer(serializers.ModelSerializer):
    class Meta:
        model = Homonym
        fields = '__all__'


class WordSerializer(serializers.ModelSerializer):
    homonyms = HomonymSerializer(many=True)
    
    class Meta:
        model = Word
        fields = '__all__'

Вопрос: В настоящее время отображаются все омонимы, независимо от того, приняты они или нет. Как я могу ограничить вложенный сериализатор, чтобы он включал только омонимы с publishing_status="accepted"?

Вот мое мнение:

class WordRetrieveView(RetrieveAPIView):
    serializer_class = WordSerializer
    queryset = Word.objects.all().filter(publishing_status='accepted')

Мое текущее решение состоит в том, чтобы определить поле homonyms как SerializerMethodField() и фильтровать набор запросов здесь (у меня есть ощущение, что это не лучший способ и не способ django):

class WordSerializer(serializers.ModelSerializer):
        homonyms = serializers.SerializerMethodField()
        
        class Meta:
            model = Word
            fields = '__all__'

        @staticmethod
        def get_homonyms(obj):
            homonyms = Homonym.objects.all().filter(publishing_status='accepted', homonym_id=obj.id)
            return [HomonymSerializer(Word.objects.get(id=h.homonym_id)).data for h in homonyms]

Ваш основной набор запросов будет влиять только на результаты, возвращаемые Word, но не на связанные омонимы. Поэтому вам нужно применить тот же фильтр к связанным объектам, если вы хотите, чтобы возвращалось только определенное подмножество.

В этом случае достаточно просто изменить ваш набор запросов на:

Word.objects.filter(publishing_status='accepted').prefetch_related(
    Prefetch('homonyms', queryset=Homonym.objects.filter(publishing_status='accepted'))
)

Это позволит получить все Word, которые приняты, а также получить любые связанные омонимы на слово, которые также приняты.

Вернуться на верх