Django rest framework, использовать разные сериализаторы в одном ModelViewSet

на самом деле, нет причин блокировать доступ к объекту для чтения. вы только хотите заблокировать его во время записи. это именно то, что блокирует читатель-писатель. он не блокирует объект, если нет операций записи. он повышает производительность и предотвращает взаимоблокировки. см. следующие ссылки для более подробных объяснений:

wikipedia codeproject

152
задан Håken Lid 21 April 2018 в 10:41
поделиться

1 ответ

Хотя предопределяя несколько Сериализаторов в или путь или другой, действительно кажется, наиболее очевидно , зарегистрировал путь, FWIW, там альтернативный подход, который привлекает другой зарегистрированный код и который включает передающие аргументы сериализатору, поскольку он инстанцируют. Я думаю, что это, вероятно, имело бы тенденцию более стоить, если бы необходимо было генерировать логику на основе различных факторов, таких как пользовательские администраторские уровни, называемое действие, возможно, даже атрибуты экземпляра.

первая часть загадки является документацией относительно динамично изменение сериализатора при инстанцировании . Та документация не объясняет, как назвать этот код от viewset или как изменить состояние только для чтения полей после того, как им подражали - но это не очень твердо.

вторая часть - get_serializer метод также документируется - (просто немного далее ниже на страницу от get_serializer_class в соответствии с 'другими методами'), таким образом, должно быть безопасно полагаться (и источник очень прост, который, надо надеяться, означает меньше шанса непреднамеренных побочных эффектов, следующих из модификации). Проверьте источник под GenericAPIView (ModelViewSet - и все другие созданные в viewset классах, которыми это кажется - наследовались GenericAPIView, который, определяет get_serializer.

Помещение двух вместе Вы могли сделать что-то вроде этого:

В файле сериализаторов (для меня base_serializers.py):

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""

def __init__(self, *args, **kwargs):
    # Don't pass the 'fields' arg up to the superclass
    fields = kwargs.pop('fields', None)

    # Adding this next line to the documented example
    read_only_fields = kwargs.pop('read_only_fields', None)

    # Instantiate the superclass normally
    super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

    if fields is not None:
        # Drop any fields that are not specified in the `fields` argument.
        allowed = set(fields)
        existing = set(self.fields)
        for field_name in existing - allowed:
            self.fields.pop(field_name)

    # another bit we're adding to documented example, to take care of readonly fields 
    if read_only_fields is not None:
        for f in read_only_fields:
            try:
                self.fields[f].read_only = True
            exceptKeyError:
                #not in fields anyway
                pass

Затем в Вашем viewset Вы могли бы сделать что-то вроде этого:

class MyViewSet(viewsets.ModelViewSet):
    # ...permissions and all that stuff

    def get_serializer(self, *args, **kwargs):

        # the next line is taken from the source
        kwargs['context'] = self.get_serializer_context()

        # ... then whatever logic you want for this class e.g:
        if self.action == "list":
            rofs = ('field_a', 'field_b')
            fs = ('field_a', 'field_c')
        if self.action == “retrieve”:
            rofs = ('field_a', 'field_c’, ‘field_d’)
            fs = ('field_a', 'field_b’)
        #  add all your further elses, elifs, drawing on info re the actions, 
        # the user, the instance, anything passed to the method to define your read only fields and fields ...
        #  and finally instantiate the specific class you want (or you could just
        # use get_serializer_class if you've defined it).  
        # Either way the class you're instantiating should inherit from your DynamicFieldsModelSerializer
        kwargs['read_only_fields'] = rofs
        kwargs['fields'] = fs
        return MyDynamicSerializer(*args, **kwargs)

И это должно быть этим! Используя MyViewSet должен теперь инстанцировать Вашего MyDynamicSerializer с аргументами, которые Вы хотели бы - и предположение, что Ваш сериализатор наследовался Вашему DynamicFieldsModelSerializer, он должен знать, что сделать.

, Возможно, который стоит упомянуть, то, что это может, имеет специальный смысл, если Вы хотите адаптировать сериализатор некоторыми другими способами †¦, например, сделать, вещам нравится, берут в списке read_only_exceptions и используют его, чтобы добавить в белый список, а не поместить в черный список поля (который я склонен делать). Я также нахожу полезным установить поля на пустой кортеж, если не передал, и затем просто удалите проверку ни на Один..., и я установил свои полевые определения на моих Сериализаторах наследования к' весь '. Это не означает полей, которые не передаются, когда инстанцирование сериализатора выживает случайно, и я также не должен сравнивать вызов сериализатора с наследовавшимся определением класса сериализатора для знания то, что было включено..., например, в init DynamicFieldsModelSerializer:

# ....
fields = kwargs.pop('fields', ())
# ...
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
# ....

NB, Если я просто хотел два или три класса, которые отобразились на отличные действия и/или я не хотел специально динамического поведения сериализатора, я мог бы хорошо использовать один из подходов, упомянутых другими здесь, но я думал этот, который стоит представить как альтернативу, особенно учитывая ее другое использование.

0
ответ дан 23 November 2019 в 21:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: