Django Rest Framework: serializing/deserializing 一个计算字段
Django Rest Framework: serializing/deserializing a calculated field
我刚开始使用 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)
我们的想法是读取用户刚刚选择的 account
记录中的 vat_perc
值,然后执行计算以确定 total_amount
值,然后将其保存在数据库的 entry
记录中(我知道由于数据库中的数据重复,有些人会认为这是次优的;无论如何请关注我)。
total_amount
字段应在请求时定期序列化。相反,序列化程序不应该为反序列化做任何事情,因为模型中 save
方法的覆盖会在创建或修改发生时负责更新值。如果我正确地获得了文档,这意味着将序列化器 class 中的 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)
但这是我得到的错误:
Got a TypeError
when calling Entry.objects.create()
. This may be because you have a writable field on the serializer class that is not a valid argument to Entry.objects.create()
. You may need to make the field read-only, or override the EntrySerializer.create() method to handle this correctly.
Original exception text was: int() argument must be a string, a bytes-like object or a number, not 'Account'.
最后一句话对我来说特别难懂。我弄错了什么吗?有什么提示吗?
提前致谢。
感谢Claudiu。在序列化程序中使用 SlugRelatedField
class 和 decimal.Decimal
type 而不是 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")
我刚开始使用 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)
我们的想法是读取用户刚刚选择的 account
记录中的 vat_perc
值,然后执行计算以确定 total_amount
值,然后将其保存在数据库的 entry
记录中(我知道由于数据库中的数据重复,有些人会认为这是次优的;无论如何请关注我)。
total_amount
字段应在请求时定期序列化。相反,序列化程序不应该为反序列化做任何事情,因为模型中 save
方法的覆盖会在创建或修改发生时负责更新值。如果我正确地获得了文档,这意味着将序列化器 class 中的 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)
但这是我得到的错误:
Got a
TypeError
when callingEntry.objects.create()
. This may be because you have a writable field on the serializer class that is not a valid argument toEntry.objects.create()
. You may need to make the field read-only, or override the EntrySerializer.create() method to handle this correctly. Original exception text was: int() argument must be a string, a bytes-like object or a number, not 'Account'.
最后一句话对我来说特别难懂。我弄错了什么吗?有什么提示吗? 提前致谢。
感谢Claudiu。在序列化程序中使用 SlugRelatedField
class 和 decimal.Decimal
type 而不是 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")