Как добавить ситуационное поле в сериализатор?

#django #django-rest-framework

#django #django-rest-framework

Вопрос:

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

Например, хранилище ниже:

 class Store(models.Model):
    owner = models.ForeignKey(Account, on_delete=models.DO_NOTHING)
    name = models.CharField(max_length=128)
    license= models.CharField(max_length=128)
    menu = models.ManyToManyField(Product)
    address = models.ForeignKey(Address, on_delete=models.DO_NOTHING, blank=True, null=True)

class StoreSerializer(serializers.ModelSerializer):
    owner = AccountSerializer(read_only=True)
    menu = ProductSerializer(many=True, read_only=True)
    address = AddressSerializer(read_only=True)

    class Meta:
        model = Store

        fields = ('owner', 'name', 'menu', 'address', 'license')
  

В этом примере я хочу, чтобы все пользователи могли находить хранилища, но license поле должно быть доступно CRUD только в том случае, если пользователь является владельцем этого объекта.

Каково оптимальное решение в этом случае? Пока что мои варианты кажутся:

A) Создайте отдельный сериализатор для типа owner

Б) Превратить license в SerializerMethodField и при необходимости предоставить его оттуда

Мне интересно, какая практика лучше и есть ли другие, более элегантные способы сделать это.

Комментарии:

1. лучшей практикой является вариант A IMO, и это то, что я видел, как делают другие. В будущем вам будет проще расширять / модифицировать код и у вас будет лучшая организация кода. Выбор того, какой сериализатор использовать, также логически принадлежит уровню представления, поскольку это определяет представление. Представления DRF изначально предусматривают такого рода переключение сериализатора.

2. У вас должен быть отдельный сериализатор, и вы должны решить, какой сериализатор использовать для просмотра. Поскольку авторизация происходит в режиме просмотра.

Ответ №1:

Лучшим способом, на мой взгляд, было бы создать два разных сериализатора, в зависимости от пользователя, который собирается выполнить запрос. Перефразировка из DRF Docs:

get_serializer_class(self)

Возвращает класс, который должен использоваться для сериализатора. По умолчанию возвращается атрибут serializer_class.

Может быть переопределено для обеспечения динамического поведения, такого как использование разных сериализаторов для операций чтения и записи или предоставление разных сериализаторов разным типам пользователей.

Это дополнительно позволит вам проверять условие Store владения внутри переопределенного get_serializer_class представления, которое наследуется от GenericAPIView класса, и выбирать между использованием того или иного сериализатора. Иллюстрирующий это:

 class UserList(generics.ListCreateAPIView):

    queryset = Store.objects.all()
    permission_classes = (IsAuthenticated,)

    def get_serializer_class(self):
        # Here you will provide the implementation of the checking function
        if self.request.user.is_store_owner():
            return PrivateStoreSerializer
        return PublicStoreSerializer
  

Комментарии:

1. Специфично для строки if self.request.user.is_store_owner(): как мне получить доступ к запрашиваемому объекту для сравнения с зарегистрированным пользователем?

2. @SaumilPatel На самом деле, та же самая переменная self.request.user здесь выдаст вам пользователя, который выполнил запрос.