模型:

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(通常在5%左右),并将其保存到特定的xx%
(明白了吗?如果需要,我可以举个例子)
基本公式是:
Dvd.final_value = Dvd.price * Dvd.sold_copies
Dvd.licence_dvd.computed_value = Dvd.final_value * Dvd.licence_dvd.percent

第一个是有效的,但是第二个是。。。很棘手。
如果每个xx%只有一个final_value,则很容易(validated_data.pop,save thedvd,save thelicence.computed_value)。问题是每一个licence在数据库中有多个dvd,因此licence返回多个对象。
遍历dvd可以得到:
OrderedDict([('percent', Decimal('0.5')), ('computed_value', Decimal('1234'))])

每个licences(这只是一个例子)。
问题:
我这样做对吗?如果某些值是由公式重新计算的,那么定义和计算应该放在哪里?在API/serializer/front-end级别?
在update函数中,instance和validated_数据有什么区别?我知道已验证的_数据是已验证的传入数据,但何时以及如何访问/修改其(或实例的)变量?
如何修改dvd函数中的licence_dvd数据?
非常感谢您提供的有用信息!

最佳答案

首先,我在你的例子中找不到多对多的关系,所以问题标题似乎有误导性(本质上是一对多,许多许可证可以指一张DVD)。对于这些问题:
我确信序列化程序不是定义业务逻辑的正确位置(而更新计数器正是其中的一部分)。我建议把它放在风景区。序列化程序只能用于序列化/反序列化数据(例如,将数据从JSON转换为对象并返回);
实例和验证数据之间的区别是,实例是数据库中现有行的表示,您将要更改和验证。
如前所述,序列化程序不是合适的位置。否则,您必须考虑到dvd.license_dvd本质上是一个集合,而不是一个值(实际上,在您的逻辑中,每个dvd可以有多个许可证)。因此,要更新许可证,必须遍历它们:
for license in dvd.license_dvd: do your updates here for each license
如果每个DVD实际上只有一个许可证,请考虑改用OneToOneField,这更为合适。

关于python - DRF在序列化程序update()调用中更新ManyToMany,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28049768/

10-10 23:09