Django REST Framework и общие отношения

Проблема

У меня есть модель со следующими стандартными универсальными полями внешнего ключа:

content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
event_object = generic.GenericForeignKey('content_type', 'object_id')

Согласно документам REST framework, я могу сделать следующее, чтобы правильно сериализовать это:

class WhateverSerializer(serializers.ModelSerializer):
    event_object = serializers.RelatedField(source='event_object')

Это отлично работает, однако в двух других связанных ситуациях я не могу заставить все работать:

  1. Я хотел бы использовать HyperlinkedRelatedField. Для этого поля требуется аргумент view_name, который я не могу объявить, поскольку имя представления зависит от связанной модели. Я решил эту проблему, используя SerializerMethodField, создав экземпляр HyperlinkedIdentityField во время выполнения и вернув его метод field_to_native (см. фрагмент ниже). Это не кажется очень элегантным.
  2. Я хотел бы вложить связанный объект непосредственно в сериализацию, сказав event_object = SoAndSoSerializer(source='event_object'). Единственное решение, которое я вижу, — пройтись по каждому *Serializer, который я определил, и проверить, какая из них имеет правильную модель, а затем использовать ее. Опять же, это не кажется очень элегантным.

Вопросы

предназначено ли HyperlinkRelatedField для работы в общих отношениях? Я просто делаю ошибку? Есть ли очевидное решение, как правильно выбрать *Serializer, которого мне не хватает?

Фрагмент кода

Неэлегантное решение, упомянутое в пункте 1 выше:

class WhateverSerializer(DefaultSerializer):

    event_object_url = serializers.SerializerMethodField('get_related_object_url')
    # ...

    def get_related_object_url(self, obj):
        obj = obj.event_object
        default_view_name = '%(model_name)s-detail'
        format_kwargs = {
            'app_label': obj._meta.app_label,
            'model_name': obj._meta.object_name.lower()
        }
        view_name = default_view_name % format_kwargs
        s = serializers.HyperlinkedIdentityField(source=obj, view_name=view_name)
        s.initialize(self, None)
        return s.field_to_native(obj, None)

person Ben Graham    schedule 21.01.2013    source источник
comment
Обратите внимание, что вам нужно использовать аргумент «источник» для поля только в том случае, если источник отличается от имени поля. Вы можете отбросить его в случае 'event_object'.   -  person Tom Christie    schedule 22.01.2013


Ответы (1)


Вы правы, инфраструктура REST не поддерживает эти варианты использования, и мне не очевидно, как будет выглядеть дизайн, если он это сделает. Вам, вероятно, понадобится неявный реестр model->view (для случая с гиперссылкой) и model->serializer (для вложенного случая), что, я не думаю, мне очень понравится.

Самый простой способ сделать то, что вам нужно, - это, вероятно, создать подкласс ManyRelatedField и создать настраиваемый тип поля, переопределив to_native(self, obj) для сериализации каждого объекта в наборе именно так, как вы этого хотите.

person Tom Christie    schedule 22.01.2013
comment
Спасибо за проверку здравомыслия, Том. Я не задавал вопрос, на который был бы «правильный» ответ (плохая форма), но думаю, что вы более или менее попали в точку. Ваше здоровье. - person Ben Graham; 22.01.2013