Django 休息框架。更新嵌套对象

新手上路,请多包涵

我在更新嵌套对象时遇到问题。

所以我有一个结构类似于这个的模型:

 class Invoice(models.Model):
    nr = models.CharField(max_length=100)
    title = models.CharField(max_length=100)

class InvoiceItem(models.Model):
    name = models.CharField(max_length=100)
    price = models.FloatField()
    invoice = models.ForeignKey(Invoice, related_name='items')

我需要从父对象创建子对象,我的意思是在创建 InvoiceItems 对象时直接创建 Invoice 对象。为此,我编写了以下序列化程序:

 class InvoiceItemSerializer(serializers.ModelSerializer):
    invoice = serializers.PrimaryKeyRelatedField(queryset=Invoice.objects.all(), required=False)
    class Meta:
        model = InvoiceItem

class InvoiceSerializer(serializers.ModelSerializer):
    items = InvoiceItemSerializer(many=True)

    class Meta:
        model = Invoice

    def create(self, validated_data):
        items = validated_data.pop('items', None)
        invoice = Invoice(**validated_data)
        invoice.save()
        for item in items:
            InvoiceItem.objects.create(invoice=invoice, **item)
        return invoice

到目前为止,创建/读取/删除方法工作正常,除了 update 。我认为下面的逻辑应该是正确的,但它遗漏了一些东西。

 def update(self, instance, validated_data):
    instance.nr = validated_data.get('nr', instance.nr)
    instance.title = validated_data.get('title', instance.title)
    instance.save()

    # up till here everything is updating, however the problem appears here.
    # I don't know how to get the right InvoiceItem object, because in the validated
    # data I get the items queryset, but without an id.

    items = validated_data.get('items')
    for item in items:
        inv_item = InvoiceItem.objects.get(id=?????, invoice=instance)
        inv_item.name = item.get('name', inv_item.name)
        inv_item.price = item.get('price', inv_item.price)
        inv_item.save()

    return instance

任何帮助将非常感激。

原文由 dimmg 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 413
2 个回答

这是我完成任务的方式:

我添加了一个 id 字段到 InvoiceItemSerializer

 class InvoiceItemSerializer(serializers.ModelSerializer):
    ...
    id = serializers.IntegerField(required=False)
    ...

以及 InvoiceSerializer 的更新方法

def update(self, instance, validated_data):
    instance.nr = validated_data.get('nr', instance.nr)
    instance.title = validated_data.get('title', instance.title)
    instance.save()

    items = validated_data.get('items')

    for item in items:
        item_id = item.get('id', None)
        if item_id:
            inv_item = InvoiceItem.objects.get(id=item_id, invoice=instance)
            inv_item.name = item.get('name', inv_item.name)
            inv_item.price = item.get('price', inv_item.price)
            inv_item.save()
        else:
            InvoiceItem.objects.create(account=instance, **item)

    return instance

同样在 create 方法中,如果通过,我将弹出 id

原文由 dimmg 发布,翻译遵循 CC BY-SA 3.0 许可协议

所有这些解决方案对我来说似乎都太复杂或太具体,我最终使用 了此处教程 中的代码,这些代码 非常简单且可重用

 from rest_framework import serializers
from django.contrib.auth import get_user_model
from myapp.models import UserProfile

# You should already have this somewhere
class UserProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserProfile
        fields = ['nested', 'fields', 'you', 'can', 'edit']

class UserSerializer(serializers.ModelSerializer):
    # CHANGE "userprofile" here to match your one-to-one field name
    userprofile = UserProfileSerializer()

    def update(self, instance, validated_data):
        # CHANGE "userprofile" here to match your one-to-one field name
        if 'userprofile' in validated_data:
            nested_serializer = self.fields['userprofile']
            nested_instance = instance.userprofile
            nested_data = validated_data.pop('userprofile')

            # Runs the update on whatever serializer the nested data belongs to
            nested_serializer.update(nested_instance, nested_data)

        # Runs the original parent update(), since the nested fields were
        # "popped" out of the data
        return super(UserSerializer, self).update(instance, validated_data)

编辑:修正错误,我在尝试更新嵌套字段之前添加了对嵌套字段是否存在的检查。

原文由 Preston Badeer 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题