Django Rest Framework-创建和更新父子关系

时间:2019-01-03 10:14:01

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

我正在尝试使用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的实例(但尚不存在)。

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

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

2 个答案:

答案 0 :(得分:1)

您没有正确使用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

请注意,在id的OOP体系结构Article中已经隐含了文章ID,因此在字段名前面加上article是一个非常多余且不明智的做法。再说一次,您可能想使用Django自动生成的id字段而不是重新定义它,除非您想以某种方式自定义它(当前在您的代码中并不明显)

答案 1 :(得分:0)

  1. 您可以看到django rest框架文档:https://www.django-rest-framework.org/api-guide/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

希望能对您有所帮助