在Django Rest Framework中使用自定义相关管理器序列化反向外键字段

时间:2016-04-09 04:17:27

标签: django django-models django-rest-framework

所有

我有2个模型通过外键链接在一起。我在反向字段上使用自定义相关管理器。

models.py:

class Foo(models.Model):
  name = models.CharField(max_length=23)
  bar = models.ForeignKey("Bar", related_name="foos")

class Bar(models.Model):
  name = models.CharField(max_length=42)
  my_custom_manager = MyCustomManager()

class MyCustomManager(models.Manager):
  use_for_related_fields = True

  def get_queryset(self):
    if self.instance.is_special():
      return do_something_special() # returns a list of Foos
    return super(MyCustomManager, self).get_queryset()

要使用此功能,请使用以下代码:

my_bar_instance.foos.add(my_foo_instance)
my_bar_instance.foos(manager="my_custom_manager").all()

我知道这是一个人为的例子,但请相信我有时候在向这个字段添加对象时我需要做非标准的事情。无论如何,这段代码运行正常。问题是当我尝试序列化它时。

serializers.py:

class FoosField(serializers.RelatedField):

    queryset = Foo.objects.all()

    list_serializer_class = ListSerializer

    def to_representation(self, value):        
        if not value:
            return {}

        from .some_other_package import FooSerializer
        serializezr = FooSerializer()
        representation = serializezr.to_representation(value)
        return representation

    def to_internal_value(self, data):
        if not data:
            return None

        from .some_other_package import FooSerializer
        serializer = FooSerializer()
        internal_value = serializer.to_internal_value(data)
        return internal_value

class BarSerializer(ModelSerializer):

    class Meta:
        model = Bar
        fields = (
            'id',
            'name',
            'foos',
        )

    foos = BarField(many=True, required=False, allow_null=True, queryset=Foo.objects.all())

它只输出“foos”字段的空列表。我怀疑这是因为它直接调用反向关系字段foos而不是指定自定义管理器foos(manager="my_custom_manager")。关于如何告诉Django Rest Framework使用自定义管理器的任何想法?

由于

2 个答案:

答案 0 :(得分:1)

使用SerializerMethodField定义一个函数,您可以在其中处理所需的查询集。例如,另请参见this question

答案 1 :(得分:0)

可以做到。但这很难看:

<强> serializers.py:

class FoosChildField(ManyRelatedField):

  def get_attribute(self, instance):
    manager = self.child_relation.manager
    if manager:
      relationship = getattr(instance, manager.get_name())
      return relationship.all() if (hasattr(relationship, 'all')) else relationship
    super(FoosChildField, self).get_attribute(instance)

class FoosField(serializers.RelatedField):

    queryset = Foo.objects.all()

    list_serializer_class = ListSerializer

    def __init__(self, **kwargs):
      manager = kwargs.pop("manager", None)
      super(FoosField, self).__init__(**kwargs)
      self.manager = manager

    @classmethod
    def many_init(cls, *args, **kwargs):        
      list_kwargs = {'child_relation': cls(*args, **kwargs)}
      for key in kwargs.keys():
        if key in MANY_RELATION_KWARGS:
            list_kwargs[key] = kwargs[key]
      return FoosChildField(**list_kwargs)

    def to_representation(self, value):        
        if not value:
            return {}

        from .some_other_package import FooSerializer
        serializezr = FooSerializer()
        representation = serializezr.to_representation(value)
        return representation

    def to_internal_value(self, data):
        if not data:
            return None

        from .some_other_package import FooSerializer
        serializer = FooSerializer()
        internal_value = serializer.to_internal_value(data)
        return internal_value

class BarSerializer(ModelSerializer):

    class Meta:
        model = Bar
        fields = (
            'id',
            'name',
            'foos',
        )

    foos = BarField(many=True, required=False, allow_null=True, queryset=Foo.objects.all(), manager=Bar.my_custom_manager)

我添加了一个新课程(FoosChildField)和两个新方法(__init__&amp; many_init)。

基本上,我将管理器传递给DRF相关的字段实例,后者又将其传递给DRF“子”字段(因为这是一个列表序列化器)。 get_attribute fn使用该经理获取实际值。

呸。