【问题标题】:Django serialize child model from inheritance fieldDjango从继承字段序列化子模型
【发布时间】:2020-06-15 01:48:27
【问题描述】:

我正在使用 DRF,但我的模型似乎存在设计问题:

背景: 我正在做一个财务管理的个人项目,所以我有SavingsAccountCreditCardIncomes 的模型(这确实很简化,但我认为这足以看出问题所在)。

问题: 在收入中,我应该能够跟踪我向哪个账户添加了钱,但这可能是一个储蓄账户或信用卡,所以我制作了另一个模型,它具有两者的共同属性,称为Account

我使用InheritanceManager 让它更容易一些。

from model_utils.managers import InheritanceManager

class Account(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=120)
    balance = models.DecimalField(decimal_places=4, max_digits=12)
    objects = InheritanceManager()

    def get_child(self):
        return Account.objects.get_subclass(pk=self.pk)

class SavingsAccount(Account):
    bank = models.CharField(max_length=120)
    is_investment = models.BooleanField(default=0)


class CreditCard(Account):
    cut = models.IntegerField()
    pay = models.IntegerField()
    bank = models.CharField(max_length=120)
    credit = models.DecimalField(decimal_places=4, max_digits=12)

    @property
    def used(self):
        return self.credit - self.balance

class Income(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    amount = models.DecimalField(decimal_places=4, max_digits=12)
    account = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="incomes")
    description = models.TextField()
    date = models.DateField()

有了这个,我可以与账户进行交互:income = Income.objects.select_related("account").first() 然后income.account.get_child() 来检索 SavingsAccount 或 CreditCard 对象,问题出在序列化程序上,因为我想发送子对象Account 对象。

我目前(不完整)的解决方案: 使用我得到的rest-framework-generic-relations

class IncomeSerializer(serializers.ModelSerializer):
    account = GenericRelatedField({
        CreditCard: CreditCardSerializers(),
        SavingsAccount: SavingsAccountSerializers(),
    })
    class Meta:
        Model = Income
        fields = ("id", "amount", "account", "description")

这会失败,因为序列化程序获取的帐户对象是 Account 类型,我怎样才能获得带有帐户子类而不是默认子类的收入查询集?

这是个坏主意吗?我应该如何实现这样的事情?最好只发送帐户对象的 id,然后对该对象进行另一个请求?

提前非常感谢,我尝试提供所有需要的信息,但如果我应该添加更多信息,请告诉我。

我一直避免使用 ContentType,因为我认为这里不需要它。

【问题讨论】:

    标签: python django django-rest-framework generic-relations


    【解决方案1】:

    好吧,现在我是这样做的:

    class AccountSerializer(serializers.ModelSerializer):
        def to_representation(self, value):
            child = value.get_child()
            if isinstance(child, SavingsAccount):
                serializer = SavingsAccountSerializer(child)
            elif isinstance(child, Wallet):
                serializer = WalletSerializer(child)
            else:
                raise Exception('Unexpected type of tagged object')
    
            return serializer.data
    
        class Meta:
            model = Account
    
    class WalletSerializer(serializers.ModelSerializer):
        class Meta:
            model = Wallet
            fields = ('__all__')
    
    
    class SavingsAccountSerializer(serializers.ModelSerializer):
        class Meta:
            model = SavingsAccount
            fields = ('__all__')
    
    
    class IncomeSerializer(serializers.ModelSerializer):
        account = AccountSerializer(read_only=True)
        class Meta:
            model = Income
            fields = ("__all__")
    

    我确信这不是最有效的方法,因为每个对象中的get_child 方法使用的连接使用n 查询数(其中n 是收入中的对象数),我很确定你可以用 2 个查询(每个子类一个)来完成,但我只是在学习,希望更有经验的人会发布更好的答案。

    尽管如此,我还是允许这样做,以防对像我这样从事小项目的人有所帮助。

    注意: 我只是用它来检索信息,我没有测试它来检索信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多