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

fra*_*cvs 5 django django-rest-framework

我刚开始使用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)
Run Code Online (Sandbox Code Playgroud)

想法是读取用户刚刚选择vat_perc的account记录中的值,并执行计算以确定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)
Run Code Online (Sandbox Code Playgroud)

但这是我得到的错误:

得到一个TypeError电话Entry.objects.create().这可能是因为序列化程序类上的可写字段不是有效参数Entry.objects.create().您可能需要将该字段设置为只读,或重写EntrySerializer.create()方法以正确处理此字段.原始异常文本是:int()参数必须是字符串,类似字节的对象或数字,而不是"帐户".

最后一句话对我来说听起来特别模糊.我弄错了吗?任何提示?提前致谢.

fra*_*cvs 7

感谢克劳迪乌。使用SlugRelatedField的序列化器类和decimal.Decimal类型,而不是float像我一样mistankenly。以下代码现在有效:

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)
Run Code Online (Sandbox Code Playgroud)

序列化程序.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")
Run Code Online (Sandbox Code Playgroud)