[python] Динамически ограничивающий набор запросов в связанной области



3 Answers

Вот как я это делаю:

class PurchaseList(viewsets.ModelViewSet):
    ...
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        context = self.get_serializer_context()
        return serializer_class(*args, request_user=self.request.user, context=context, **kwargs)

class PurchaseSerializer(serializers.ModelSerializer):
    ...
    def __init__(self, *args, request_user=None, **kwargs):
        super(PurchaseSerializer, self).__init__(*args, **kwargs)
        self.fields['user'].queryset = User._default_manager.filter(pk=request_user.pk)
Question

Используя Django REST Framework, я хочу ограничить, какие значения могут использоваться в связанной области в создании.

Например, рассмотрим этот пример (на основе примера фильтрации на http://django-rest-framework.org/api-guide/filtering.html , но он изменился на ListCreateAPIView):

class PurchaseList(generics.ListCreateAPIView)
    model = Purchase
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        user = self.request.user
        return Purchase.objects.filter(purchaser=user)

В этом примере, как я могу гарантировать, что при создании покупатель может быть равен только self.request.user, и что это единственное значение, которое отображается в раскрывающемся списке формы в просматриваемом API-интерфейсе API?




По запросу @ gabn88, как вы уже знаете, с DRF 3.0 и выше, нет простого решения. Даже если вам удастся найти решение, оно не будет красивым и, скорее всего, не сработает на последующих версиях DRF, поскольку оно переопределит кучу источника DRF, который к тому времени будет изменен.

Я забыл точную реализацию, которую я использовал, но идея состоит в том, чтобы создать два поля в сериализаторе, одно ваше нормальное поле сериализатора (скажем, PrimaryKeyRelatedField и т. Д.), А другое поле - поле метода сериализатора, результаты которого будут заменены в некоторых случаях (например, на основе запроса, пользователя запроса или чего-то еще). Это будет сделано на конструкторе сериализаторов (т.е.: init )

Поле метода serializer вернет вам пользовательский запрос. Вы побьете и / или замените эти результаты полей так, чтобы результаты вашего поля метода сериализатора были присвоены нормальному / серийному сериализатору поля (PrimaryKeyRelatedField и т. Д.) Соответственно. Таким образом, вы всегда имеете дело с этим одним ключом (поле по умолчанию), в то время как другой ключ остается прозрачным в вашем приложении.

Наряду с этой информацией все, что вам действительно нужно, это изменить это: http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields




В django 3.0 метод get_fields был удален. Но аналогичным образом вы можете сделать это в функции init сериализатора:

class PurchaseSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Purchase

    def __init__(self, *args, **kwargs):
        super(PurchaseSerializer, self).__init__(*args, **kwargs)
        if 'request' in self.context:
            self.fields['purchaser'].queryset = permitted_objects(self.context['view'].request.user, fields['purchaser'].queryset)

Я добавил проверку if, так как если вы используете PurchaseSerializer в качестве поля в другом сериализаторе при методах get, запрос не будет передан в контекст.




Я сделал следующее:

class MyModelSerializer(serializers.ModelSerializer):
    myForeignKeyFieldName = MyForeignModel.objects.all()

    def get_fields(self, *args, **kwargs):
        fields = super(MyModelSerializer, self).get_fields()
        qs = MyModel.objects.filter(room=self.instance.id)
        fields['myForeignKeyFieldName'].queryset = qs
        return fields



Related