Как я могу использовать связанное поле в SlugRelatedField? - PullRequest
1 голос
/ 30 апреля 2020

У меня есть следующие структуры

class State(models.Model):
    label = models.CharField(max_length=128)
    ....

class ReviewState(models.Model):
    state = models.ForeignKey(State, on_delete=models.CASCADE)
    ...

class MySerializer(serializers.HyperlinkedModelSerializer):
    state = serializers.SlugRelatedField(queryset=ReviewState.objects.all(), slug_field='state__label', required=False)
class Meta:
    model = MyModel
    fields = [
        'id',
        'state', # this points to a ReviewState object
        ....
      ]

Вместо этого я пытаюсь использовать метку объекта State в качестве поля. Но не похоже, что djangorestframework нравится идея использования __ для поиска полей слагов. Было бы возможно сделать это? Если бы это было:

class MySerializer(serializers.HyperlinkedModelSerializer):
    state = serializers.SlugRelatedField(queryset=State.objects.all(), slug_field='label', required=False)

, это не было бы проблемой, но я вместо этого пытаюсь использовать ReviewState. Я также пытаюсь избежать использования ReviewStateSerializer, так как полученный json будет выглядеть так:

{...
'state': {'state': 'Pending'}}
}

1 Ответ

0 голосов
/ 01 мая 2020

Интересный вопрос, и хорошо поставленный.

Использование SlugRelatedField('state__label', queryset=...) работает нормально, с 1 предупреждением: просто вызывается queryset.get(state__label="x"), что приводит к ошибкам, если нет точного 1 совпадения.

1 ) Напишите произвольное поле?

Наследовать от SlugRelatedField и переопределить to_internal_value(), возможно, вызвав .first() вместо .get() или любой другой лог c, который вам нужен.

2) Переоцените это отношение, может быть, его 1 к 1? поле выбора?

Я немного озадачен тем, как все это будет работать, поскольку вы можете иметь «1 ко многим» с State => ReviewState. По умолчанию поиск (если вы не делаете # 1) выдаст ошибку, когда происходит несколько совпадений.

Может быть, это ситуация 1 к 1 с моделью? Возможно, ReviewState может использовать ChoiceField вместо таблицы состояний?

Возможно, «меткой» может быть PK таблицы State, а также SlugField вместо неуникального CharField?

3) Писать разные сериализаторы для случаев List и Create

DRF не дает нам встроенного способа сделать это, но это опора на «один сериализатор, чтобы сделать все это» является причиной многих проблем, которые я вижу в SO. Просто очень трудно получить то, что вы хотите, не имея разных сериализаторов для разных случаев. Сделать это не сложно, но вот пример, использующий переопределение:

from rest_framework import serializers as s

class MyCreateSerializer(s.ModelSerializer):
    state = s.SlugRelatedField(...)
    ...

class MyListSerializer(s.ModelSerializer):
    # use dotted notation, serializers read *object* attributes
    state = s.CharField(source="state.state.label")
    ...

class MyViewSet(ModelViewSet):
    queryset = MyModel.objects.select_related('state__state')
    ...
    def get_serializer_class(self):
        if self.action == "create":
            return MyCreateSerializer
        else:
            return MyListSerializer

...