模型:
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/