python - Django Rest Framework - 创建和更新父子关系
问题描述
我正在尝试使用 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
解决方案
您没有get_or_create
正确使用该方法。它接受kwargs
用于查找对象的对象,如果不存在,则创建它们,并从defaults
.
这意味着如果您将新值传递给 update as 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
为 a以防止这种情况发生。OneToOneField
您可以get_or_create
在Django 文档中了解更多信息
附带说明一下,在 OOP 架构id
中Article
已经暗示了文章 ID,因此article
在您的字段名称之前添加是一种非常多余和不好的做法。同样,您可能希望使用 Django 自动生成的 id 字段而不是重新定义它,除非您想以某种方式自定义它,这在您的代码中目前并不明显
推荐阅读
- angular - Browserify for Angular,如何修复:“无法解析 ApplicationModule 的所有参数”
- c# - 如何在 C# 中使用 select count() as ...
- jenkins - 如何在 Jenkins 中更改 Invoke Gradle 脚本的默认包装器位置
- groovy - Groovy 脚本在获取 22k 行时挂起
- sql - sql中的累计和
- html - 为什么 HR 标签不是 Internet Explorer 和 Microsoft Edge 浏览器的中间屏幕
- mysql - 这个 SQL 命令的语法有什么问题
- java - 更新:从 Java 执行 SQL 查询的问题
- python - 对 Pandas 数据框的多个查询结果
- mysql - 如何计算有多少工人休假 - mysql