Django:创建具有反向关系的嵌套对象

问题描述 投票:1回答:1

尝试创建具有反向关系的嵌套对象时遇到问题。

我正在尝试POST一个Work,但在同一时间试图POST一个是Price子级的Work

这里是我的work_model

from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
from PIL import Image

class Work(models.Model):
    user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    name = models.CharField(max_length=200)
    length = models.IntegerField(null=True)
    width = models.IntegerField(null=True)

    def save(self, *args, **kwargs):
        super(Work, self).save(*args, **kwargs)

        img = Image.open(self.image.path)

        if img.height > 300 or img.width > 300:
            output_size = (300, 300)
            img.thumbnail(output_size)
            img.save(self.image.path)

    def __str__(self):
        return "{}".format(self.id)

我的price_model

from django.db import models
from .model_work import *
from .model_taxes import *
from djmoney.models.fields import MoneyField

class Price(models.Model):
    work = models.OneToOneField(Work, on_delete=models.CASCADE, related_name='price')
    price = MoneyField(max_digits=19, decimal_places=4, default_currency='USD', null=True)
    taxes = models.ForeignKey(Taxes, null=True, on_delete=models.SET_NULL)
    total = models.IntegerField(null=True)

    def __str__(self):
        return "{}".format(self.price)

还有我的taxes_model

from django.db import models

class Taxes(models.Model):
    tax_percentage = models.IntegerField(null=True)
    tax_country = models.CharField(max_length=200, null=True)
    tax_region = models.CharField(max_length=200, null=True)

    def __str__(self):
        return "{}".format(self.tax_country)

这里是我的work_serializer

from rest_framework import serializers
from ..models.model_work import Work
from .serializers_user import *
from .serializers_price import *


class WorkIndexSerializer(serializers.ModelSerializer):
    """
    Serializer listing all Works models from DB
    """
    user = UserIndexSerializer()
    price = PriceDetailsSerializer(many=False)

    class Meta:
        model = Work
        fields = [
            'id',
            'user',
            'price',
            'name',
            'image',
            'length',
            'width'
        ]

class WorkCreateSerializer(serializers.ModelSerializer):
    """
    Serializer to create a new Work model in DB
    """

    price = PriceCreateSerializer(many=False)

    class Meta:
        model = Work
        fields = [
            'user',
            'price',
            'name',
            'length',
            'width'
        ]

    def create(self, validated_data):
        price = Price.objects.create(**validated_data)
        work = Work.objects.create(**validated_data)

        return work


class WorkDetailsSerializer(serializers.ModelSerializer):
    """
    Serializer showing details of an Works model from DB
    """
    user = UserIndexSerializer()

    class Meta:
        model = Work
        fields = fields = [
            'user',
            'name',
            'image',
            'length',
            'width'
        ]

我的price_serializer

from rest_framework import serializers
from ..models.model_price import Price
from .serializers_work import *

class PriceIndexSerializer(serializers.ModelSerializer):
    """
    Serializer showing Price information when called by Work GET serializers.
    Not showing 'work' field to avoid loop.
    """
    taxes = serializers.StringRelatedField(read_only=True)
    class Meta:
        model = Price
        fields = [
            'price',
            'price_currency',
            'taxes',
            'total'
        ]
        depth = 1

class PriceDetailsSerializer(serializers.ModelSerializer):
    """
    Serializer showing Price information when called by Work GET serializers.
    Not showing 'work' field to avoid loop.
    """
    taxes = serializers.StringRelatedField(read_only=True)
    class Meta:
        model = Price
        fields = [
            'price',
            'price_currency',
            'taxes',
            'total'
        ]
        depth = 1

class PriceCreateSerializer(serializers.ModelSerializer):
    """
    Serializer to create a new Price when new Work model is created in DB
    """
    work = serializers.StringRelatedField(read_only=True)
    taxes = serializers.StringRelatedField(read_only=True)
    class Meta:
        model = Price
        fields = [
            'work',
            'price',
            'price_currency',
            'taxes',
            'total'
        ]

    def create(self, validated_data):
        work = Work.objects.create(**validated_data)
        price = Price.objects.create(**validated_data)
        taxes = Taxes.objects.create(**validated_data)
        return price

[当我尝试使用邮递员POST设置Work

{
    "user":"2",
    "name":"work 20",
    "price": 
            {
                "price":20,
                "price_currency":"EUR",
                "taxes":1,
                "total":32
            },
    "length":"50",
    "width":"60"
}

我收到错误:

TypeError at /works/
conversion from collections.OrderedDict to Decimal is not supported

[当我尝试单独POST一个Price时:

{
    "work":20,
    "price":20,
    "price_currency":"EUR",
    "taxes":1,
    "total":32
}

我收到错误:

ValueError at /prices/
Cannot assign "<Money: 20.0000 EUR>": "Work.price" must be a "Price" instance.

我找不到适用于我的案件的任何解决方案。

我在做什么磨损或丢失?

感谢您的回复!

python django nested relationship
1个回答
0
投票
1. TypeError at /works/
conversion from collections.OrderedDict to Decimal is not supported

解决方案是传递嵌套的价格字典以创建Price模型,而不是整个数据:

 def create(self, validated_data):
        price_data = validated_data.pop('price')
        work = Work.objects.create(**validated_data)
        price = Price.objects.create(**price_data)
        return price

2。

ValueError at /prices/
  Cannot assign "<Money: 20.0000 EUR>": "Work.price" must be a "Price" instance.

首先,在PriceCreateSerializer上更改工作字段,以便可以在validated_data中保存工作数据:

work = WorkDetailsSerializer()

然后:

def create(self, validated_data):
        work_data = validated_data.pop('work')
        work = Work.objects.create(**work_data)
        price = Price.objects.create(**validated_data)
        return price
© www.soinside.com 2019 - 2024. All rights reserved.