【问题标题】:How to use class attribute in its instance method in Django?如何在 Django 的实例方法中使用类属性?
【发布时间】:2020-04-23 18:43:46
【问题描述】:

我想在serializers.pyto_representation 函数中使用variation 属性。当我试图实现它时发生了错误。我想我还是不明白 Python 类的基本原理。
这是我的serializers.py

class MarketSerializer(serializers.ModelSerializer):
    regions = serializers.PrimaryKeyRelatedField(many=True, queryset=Region.objects.all())
    languages = serializers.PrimaryKeyRelatedField(many=True, queryset=Language.objects.all())
    variation = serializers.SerializerMethodField('get_product_variations')

    class Meta:
        model = Market
        fields = ['id', 'regions', 'languages', 'name', 'status', 'variation']
        depth = 1

    @staticmethod
    def get_product_variations(self):
        return Product.objects.filter(distributor__region__market=self).distinct().count()

    def to_representation(self, instance):
        if self.context['request'].method == 'GET':
            regions = RegionSerializer(instance.regions, many=True).data
            languages = LanguageSerializer(instance.languages, many=True).data

            data = {
                'id': instance.id,
                'regions': regions,
                'languages': languages,
                'name': instance.name,
                'status': instance.status,
                'variation': self.variation,
            }
            return data
        return Serializer.to_representation(self, instance)

'variation': self.variation 在可浏览的 API 上给了我这个错误:

/api/markets/ 处的 AttributeError
“MarketSerializer”对象没有“变体”属性

虽然'variation': MarketSerializer.variation'variation': self.__class__.variation 给我这个错误:

/api/markets/ 处的 AttributeError
类型对象“MarketSerializer”没有属性“变体”

编辑
'variation': variation 给我这个错误:

/api/markets/ 处的名称错误
名称“变体”未定义

【问题讨论】:

  • DRF 使用序列化器属性做了一些黑魔法。但是你还是直接调用你的方法。

标签: python django python-3.x python-2.7 django-rest-framework


【解决方案1】:

由于您试图从内部类访问外部类实例,请使用工厂方法构建内部实例并将外部实例传递给它。 当您创建内部类的实例时,我们无法保证外部类的存在

class MarketSerializer(object):
    variation = 'h'

    def MarketSerializer(self):
        return MarketSerializer.Meta(self)

    class Meta(object):
        def __init__(self, market_serializer_instance):
            self.market_serializer_instance = market_serializer_instance

        def inner_method(self):
            print(self.market_serializer_instance.variation)

【讨论】:

  • 我收到新错误:异常类型:NameError 异常值:未定义名称“变体”
  • 马龙,你的答案有效!谢谢你。虽然我有点困惑为什么class Meta(object) 中没有modelfields 属性。
  • 我只是解释了这个想法。没有时间将所有代码包含在其中。 :p 顺便说一句,我个人不推荐嵌套类,因为它没有描述任何关系,是吗?
  • "既然你试图从内部类访问外部类实例" => 你在哪里看到过这个?
  • “顺便说一句,我个人不推荐嵌套类” => 这是 DRF 序列化程序框架的一部分(并且基于 Django 的 Model 和 ModelForm 习惯用法)。内部类是元类(Python 元类)使用的命名空间。
【解决方案2】:

我不确定这应该如何工作:

@staticmethod
def get_product_variations(self):
    return Product.objects.filter(distributor__region__market=self).distinct().count()

因为,在序列化方法字段中,方法应该是这样的:

def get_product_variations(self, obj):
    # not a static method
    return Product.objects.filter(distributor__region__market=obj).distinct().count()

同样,您可以在to_represent 方法中使用该方法:

def to_representation(self, instance):
  ...
  data = {
            'id': instance.id,
            'regions': regions,
            'languages': languages,
            'name': instance.name,
            'status': instance.status,
            'variation': self.get_product_variations(instance),
        }
 ...

或者更好:

def to_representation(self, instance):
      data = super().to_representation(instance)
      if self.context['request'].method == 'GET':
            data['regions'] = RegionSerializer(instance.regions, many=True).data
            data['languages'] = LanguageSerializer(instance.languages, many=True).data
      return data

【讨论】:

  • 以前 get_product_variations 不是静态方法。因为当我试图在 data = { '...': ..., } 内部调用它时,它说 get_product_variations 需要 2 个参数。我只用一个实例来填充它。 PyCharm 给我的自动解决方案是用@staticmethod 来实现它。
  • 嗯,你用过self.get_product_variations(instance)吗? get_product_variations 是这里的对象方法。顺便说一句,我建议使用第二种解决方案作为它的清洁剂
  • 是的。我尝试在 data = {} 中使用self.get_product_variations(instance)。如果我没有应用静态方法,它也不能在类属性variation = ... 中使用。它给了我这个错误异常值:get_product_variations() 需要 1 个位置参数,但给出了 2 个
  • ruddra,我忘了回复第二个解决方案。太感谢了。我喜欢它并现在使用它。顺便说一句,我认为你打错了data = super().to_represent(instance)。不应该是data = super().to_representation(instance) 吗?或者它们确实是不同的方法。
  • 不,应该是to_representation。我现在正在修复它
猜你喜欢
  • 1970-01-01
  • 2013-03-10
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
相关资源
最近更新 更多