DRF:使用现有嵌套对象发布请求

时间:2017-08-23 13:51:35

标签: python django post serialization django-rest-framework

我是Django Rest Framework和嵌套序列化程序的新手。我有一个名为OrderSerialiser的ModelSerializer,它包含两个嵌套的ModelSerializer:ProductSerializer和ClientSerializer。

我希望在将订单请求发送到订单CreateAPI时,创建模型客户端和模型产品的新实例(仅当没有现有的实例时)。 我找到的解决方案是覆盖OrderSerializer的create方法。

当没有客户端实例并且产品具有相同的电子邮件和sku时,它工作正常,但它返回错误,表示已存在对象(客户端具有相同的电子邮件和具有相同sku的产品)在另一种情况下,并没有得到那些现有的对象,我注意到在这种情况下没有调用create方法,我认为我必须覆盖serializers.is_valid()方法,但我不知道我应该做什么确切地说。

models.py

class Client(models.Model):
    email = models.EmailField(
        verbose_name=_('Email address'),
        max_length=255,
        unique=True,
        primary_key=True
    )
    first_name = models.CharField(_('first name'), max_length=30)
    last_name = models.CharField(_('last name'), max_length=30)

class Product(models.Model):
    sku = models.CharField(
        verbose_name=_('SKU'),
        unique=True,
        max_length=120,
        primary_key=True
    )
    name = models.CharField(
        verbose_name=_('Name'),
        max_length=150
    )
    url = models.URLField(
        verbose_name=_('URL'),
        blank=True,
        null=True
    )


class Order(models.Model):
    client = models.ForeignKey(Client)
    products = models.ManyToManyField(
        Product,
        related_name= "orders",
        null=True,
        blank=True,
    )

serializers.py

class ProductSerialiser(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ('sku', 'name', 'url')

class ClientSerialiser(serializers.ModelSerializer):
    class Meta:
        model = Client
        fields = ('email','first_name', 'last_name')



class OrderSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.email')
    client = ClientSerialiser()
    products = ProductSerialiser(many=True, required=False)

    class Meta:
        model = Order
        fields = ('id', 'client', products')

    def create(self, validated_data):
        client_data = validated_data.pop('client')
        try:
            client_instance = Client.objects.get(email=client_data['email'])
        except ObjectDoesNotExist:
            client_instance = Client.objects.create(**client_data)
        if 'products' in validated_data:
            products_data = validated_data.pop('products')
            order_instance = Order.objects.create(client=client_instance, **validated_data)
            for product_data in products_data:
                try :
                    product = Product.objects.get(sku=product_data['sku'])
                except ObjectDoesNotExist:
                    product = Product.objects.create(**product_data)
                product.orders.add(order_instance)
            return order_instance

        order_instance = Order.objects.create(client=client_instance, **validated_data)
        return order_instance

2 个答案:

答案 0 :(得分:0)

Akamee,

我用来解决这类问题的一种方法基本上就是在你的serializers.py里面做

def validate(self, data):
    data = super(YourSerializer, self).validate(data)

    try:
       data['product'] = Product.objects.get(sku='bar')
    except Product.DoesNotExist:
       data['product'] = Product.object.create(sku='bar')

答案 1 :(得分:0)

这不太理想,但我确实找到了解决问题的解决方案(我等待接受它作为答案,希望别人能做得更好)

我在ClientSerializer中删除了字段电子邮件的验证器,在Productserializer中删除了字段sku,然后手动检查了对象的存在。

在serialzers.py上修改

class ProductSerialiser(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ('sku', 'name', 'url')
        extra_kwargs = {
            'sku': {
                'validators': []
            }
        }

class ClientSerialiser(serializers.ModelSerializer):
    class Meta:
        model = Client
        fields = ('email', 'first_name', 'last_name')
        extra_kwargs = {
            'email': {
                'validators': []
            }
        }



class OrderSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.email')
    client = ClientSerialiser(partial=True)
    products = ProductSerialiser(many=True, required=False, partial=True)

    class Meta:
        model = Order
        fields = ('id','client', products')


    def create(self, validated_data):
        client_data = validated_data.pop('client')
        try:
            print "**************** client exists ***********************"
            client_instance = Client.objects.get(email=client_data['email'])
        except ObjectDoesNotExist:
            print "**************** creating a client    ***********************"
            client_instance = Client.objects.create(**client_data)
        if 'products' in validated_data:
            products_data = validated_data.pop('products')
            order_instance = Order.objects.create(client=client_instance, **validated_data)
            for product_data in products_data:
                try :
                    print "**************** Product exists ***********************"
                    product = Product.objects.get(sku=product_data['sku'])
                except ObjectDoesNotExist:
                    print "**************** creating object product ***********************"
                    product = Product.objects.create(**product_data)
                product.orders.add(order_instance)
            return order_instance

        order_instance = Order.objects.create(client=client_instance, **validated_data)
        return order_instance