Django Rest Framework:序列化/反序列化计算字段

9

我刚刚开始使用Django和Django REST框架。我有以下模型:

class Account(models.Model):
    name = models.CharField(max_length=100, blank=False)
    vat_perc = models.DecimalField(max_digits=4, decimal_places=2)
    def __str__(self):
        return "ACCOUNT: {0} -- {1}".format(self.name, str(self.vat_perc))


class Entry(models.Model):
    account = models.ForeignKey(Account)
    description = models.CharField(max_length=100)
    taxable_income = models.DecimalField(max_digits=10, decimal_places=2)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True)

    def save(self, *args, **kwargs):
        selected_vat = Account.objects.get(pk=self.account).vat_perc
        self.total_amount = self.taxable_income * (100.00+selected_vat)/100.00
        super(Entry, self).save(*args, **kwargs)

想法是读取用户刚刚选择的账户记录中的vat_perc值,并进行计算以确定total_amount值,然后保存在数据库的entry记录中(我知道有些人会认为这种方法不够优化,因为数据库中存在数据重复,请仍然请跟着我)。
当请求序列化时,应定期对total_amount字段进行序列化。相反,反序列化时序列化器不应执行任何操作,因为模型中save方法的覆盖会在创建或修改时更新值。如果我正确理解了文档,所有这些都意味着将序列化器类中的total_amount字段设置为read_only。
现在,这些是我的序列化器:
class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'name', 'vat_perc',)


class EntrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Entry
        fields = ('id', 'account', 'description', 'taxable_income', 'total_amount',)

    total_amount = serializers.ReadOnlyField()
    # alternatively: total_amount = serializers.FloatField(read_only=True)

但是我得到的错误是:
调用Entry.objects.create()时出现了TypeError。这可能是因为您在序列化器类上有一个可写字段,该字段不是Entry.objects.create()方法的有效参数。您可能需要将字段设置为只读,或覆盖EntrySerializer.create()方法以正确处理此问题。 原始异常文本为:int() argument must be a string, a bytes-like object or a number, not 'Account'。 对我来说,最后一句话听起来特别难懂。我有什么误解吗?有什么提示吗? 提前致谢。

看起来你可以从查看http://www.django-rest-framework.org/api-guide/relations/受益。 - Claudiu
谢谢@Claudiu。你的评论没有直接给我答案,但它指引了我找到了答案。有一堆东西我还不明白。 - francvs
1个回答

7
感谢Claudiu的帮助。在序列化器类中使用了SlugRelatedField,并且使用了decimal.Decimal类型代替我错误地使用float。现在以下代码可以正常工作:
class Account(models.Model):
    name = models.CharField(max_length=100, blank=False)
    vat_perc = models.DecimalField(max_digits=4, decimal_places=2)
    def __str__(self):
        return "ACCOUNT: {0} -- {1}".format(self.name, str(self.vat_perc))


class Entry(models.Model):
    account = models.ForeignKey(Account)
    description = models.CharField(max_length=100)
    taxable_income = models.DecimalField(max_digits=10, decimal_places=2)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True)

    def save(self, *args, **kwargs):
        self.total_amount = self.taxable_income * (decimal.Decimal(100.00) + self.account.vat_perc) / decimal.Decimal(100.00)
        super(Entry, self).save(*args, **kwargs)

serializers.py

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
         model = Account
         fields = ('id', 'name', 'vat_perc',)


class EntrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Entry
        fields = ('id', 'account', 'description', 'taxable_income', 'total_amount',)

    total_amount = serializers.ReadOnlyField()
    account = serializers.SlugRelatedField(queryset=Account.objects.all(), slug_field="vat_perc")

1
很高兴你解决了这个问题!也许我可以建议你把这个作为被接受的答案,只要你能够这样做。 - Claudiu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接