【问题标题】:Django Rest Framework - Create and Update Parent-Child relationDjango Rest Framework - 创建和更新父子关系
【发布时间】:2019-05-29 22:03:17
【问题描述】:

我正在尝试使用 Django Rest Framework 序列化程序为我的前端创建 API,以在商店中创建/更新和删除文章。这些文章可以有多个价格(取决于时间)。因此,文章(一)与价格(多)之间存在一对多的关系。我在models.py中定义了这个:

class Article(models.Model):
    article_id = models.AutoField(primary_key=True, verbose_name="Article ID")
    article_name = models.CharField(max_length=250, verbose_name="Name")
    article_order = models.IntegerField(verbose_name="Order")

class Price(models.Model):
    price_id = models.AutoField(primary_key=True, verbose_name="Price ID")
    article_id = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name="Article ID", related_name="Prices")
    price_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="Price")

我的 serializers.py 文件如下所示:

from rest_framework import serializers
from .models import *

class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        fields = ('price_price',)

class ArticleSerializer(serializers.ModelSerializer):

    Prices = PriceSerializer(many=True)

    def create(self, validated_data):
        prices_data = validated_data.pop('Prices')
        article = Article.objects.create(**validated_data)
        for price_data in prices_data:
            Price.objects.create(article_id=article, **price_data)
        return article

    def update(self, instance, validated_data):
        prices_data = validated_data.pop('Prices')
        Article.objects.filter(article_id=instance.article_id).update(**validated_data)
        for price_data in prices_data:
            Price.objects.get_or_create(article_id=instance, **price_data)
        return instance

    class Meta:
        model = Article
        fields = '__all__'

这很好用,我可以用这个数据创建一个新的文章价格测量:(article_order 稍后将用于订购列表)

{"Prices":[{"price_price":"1"}],"article_name":"Article A","article_order":"1"}

到目前为止,一切都按预期进行。但是当我尝试更新价格时,Price.objects.get_or_create() 语句无法识别现有价格。例如:当第一个价格是 10 欧元,然后是 20 欧元,然后又是 10 欧元时,不会插入最后一个价格,因为 get_or_create 语句不会将其识别为 price 模型的新实例。这可能是有道理的,因为PriceSerializer 不会序列化price_id。但是当我将序列化程序更改为:

class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        fields = '__all__

,我无法再创建实例,因为ArticleSerializer 需要article_id 用于Price 实例(但这还不存在)。

有人知道如何解决这个问题吗? DRF 文档仅包含此类嵌套序列化程序的 create 语句。

https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

【问题讨论】:

    标签: python django django-rest-framework django-serializer


    【解决方案1】:

    您可以从此处的 Django REST Framework 文档中看到有关 serializers 的信息。

     def update(self, instance, validated_data):
         instance.email = validated_data.get('email', instance.email)
         instance.content = validated_data.get('content', instance.content)
         instance.created = validated_data.get('created', instance.created)
         return instance
    

    希望对你有帮助。

    【讨论】:

      【解决方案2】:

      您没有正确使用get_or_create 方法。 它接受用于查找对象的kwargs,如果它不存在,则创建它们,并添加来自defaults 的其他字段值。

      这意味着如果您将要更新的新值传递为kwargs,它将找不到这样的对象,因为这些字段当前具有不同的值。 相反,您应该在 kwargs 中传递不变的字段,在 defaults 中传递其余字段。

      这是你应该做的

      def update(self, instance, validated_data):
          prices_data = validated_data.pop('Prices')
          Article.objects.filter(article_id=instance.article_id).update(**validated_data)
          for price_data in prices_data:
              Price.objects.get_or_create(article_id=instance, defaults=price_data)
          return instance
      

      但是请注意,您可能会收到MutipleObjectsReturned 错误,因为一篇文章可以根据您的数据库架构有多个价格。如果不打算为每篇文章设置多个价格,您可能需要将 article_id 更改为 OneToOneField 以防止出现这种情况。

      您可以在Django docs 中阅读有关get_or_create 的更多信息

      附带说明,在 OOP 架构中,Article 中的 id 已经暗示了文章 ID,因此在字段名称前添加 article 是一种非常多余且不好的做法。同样,您可能希望使用 Django 自动生成的 id 字段而不是重新定义它,除非您想以某种方式自定义它,这在您的代码中目前并不明显

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-11
        • 2015-05-21
        • 1970-01-01
        • 1970-01-01
        • 2020-08-15
        • 2016-12-28
        • 2021-03-03
        相关资源
        最近更新 更多