Django:创建具有反向关系的嵌套对象 [英] Django: Creating Nested Objects with Reverse Relationship

查看:57
本文介绍了Django:创建具有反向关系的嵌套对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem while trying to create Nested object with a reverse relationship.

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

I'm trying to POST a Work but at the SAME time trying to POST a Price which is a Work child.

这是我的 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 时:

And when I'm trying to POST a Work with Postman:

{
    "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 时:

And when I try to POST a Price by itself:

{
    "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.

我找不到适用于我的案件的解决方案.

I can't find any solution working with my case.

我在做什么磨损或丢失?

What am I doing worng or missing?

感谢您的回复!

推荐答案

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

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

The solution is to pass the nested price dictionary to create Price model instead of the whole data:

class WorkCreateSerializer(serializers.ModelSerializer):

    price = PriceDetailsSerializer(many=False)

...

 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中保存工作数据:

First, change work field on PriceCreateSerializer, so you can have work data in validated_data:

work = WorkDetailsSerializer(many=False)

然后:

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

这篇关于Django:创建具有反向关系的嵌套对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆