DRF在序列化程序update()调用中更新ManyToMany

时间:2015-01-20 15:58:38

标签: python django rest serialization django-rest-framework

型号:

class Dvd(models.Model):
    movie = models.ForeignKey(Movie)
    price = models.DecimalField(...)
    sold_copies = models.IntegerField(...)
    final_value = models.DecimalField(...)

class Licence(models.Model):
    distribution = models.ForeignKey(Dvd, related_name="licence_dvd")
    percent = models.DecimalField(...)
    computed_value = models.DecimalField(...)

串行器:

class LicenceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Licence

class DvdSerializer(serializers.ModelSerializer):
    movie = MovieSerializer()
    licence_dvd = LicenceSerializer(many=True)

    class Meta:
        model = Dvd
        fields = ('id', 'price', 'sold_copies', 'final_value', 'movie', 'licence_dvd')

    def update(self, instance, validated_data):
        instance.price = validated_data.get('price', instance.price)
        instance.sold_copies = validated_data.get('sold_copies', instance.sold_copies)
        instance.final_value = instance.price * instance.sold_copies   # is this ok?

        # TODO recalculate the licence values

        instance.save()
        return instance

故事:

此序列化程序的目标是每次Licence.computed_value更改时更新Dvd。在每年年底,会计师会查看当年销售的所有电影,并计算每个电影的总价值(final_value)。 licences是电影制片人和公司之间的合约。每卖出dvd,公司就有xx%钱。有很多公司,因此会计师必须从相关xx%的{​​{1}}计算final_value(通常约为5%)并将其保存到特定dvd
(这是否清楚?如果需要,我可以举一个例子)
基本公式是:

licence.computed_value

第一个是工作,但第二个是......很棘手 如果每Dvd.final_value = Dvd.price * Dvd.sold_copies Dvd.licence_dvd.computed_value = Dvd.final_value * Dvd.licence_dvd.percent 只有一个licence,则很容易(validated_data.pop,保存dvd,保存licence)。问题是每个dvd数据库中有多个licences,因此dvd返回多个对象。
迭代licence_dvd给了我:

validated_data['licence_dvd']
每个OrderedDict([('percent', Decimal('0.5')), ('computed_value', Decimal('1234'))])

(这只是一个例子)。

的问题:

  • 我这样做了吗?如果通过公式重新计算某些值,那么应该放置定义和计算?在API /序列化程序/前端级别?
  • 更新功能中instance和validated_data有什么区别?我知道validated_data是经过验证的传入数据,但我应该何时以及如何访问/修改其(或实例的)变量?
  • 如何修改licence。update function?
  • 中的licence_dvd数据

非常感谢您提供任何有用的信息!

1 个答案:

答案 0 :(得分:0)

首先,我在你的例子中找不到ManyToMany关系,所以问题标题似乎有误导性(它本质上是一对多的,许多许可证可以引用一张DVD)。对于问题:

  • 我绝对相信序列化程序不是定义业务逻辑的正确位置(更新计数器只是它的一部分)。我建议把它放在视图中。序列化程序必须仅用于序列化/反序列化您的数据(例如,将其从JSON转换为对象并返回);
  • instance和validated_data之间的区别在于,instance是您要更改的数据库中现有行的表示,validated_data是您用于更新的数据(以及在更新请求中序列化的数据);
  • 正如我上面提到的,序列化程序不是正确的地方。否则,你必须考虑到dvd.license_dvd本质上是一个集合,而不是单个值(事实上,在你的逻辑中,每个DVD可以有多个许可证)。因此,为了更新许可证,您必须遍历它们:

for license in dvd.license_dvd: do your updates here for each license 如果每张DVD确实只有一个许可证,请考虑使用OneToOneField代替,更合适。