gpt4 book ai didi

python - 如何在 Django REST Framework 中创建多个模型实例而无需重复的可写嵌套序列化程序?

转载 作者:行者123 更新时间:2023-12-01 00:04:03 25 4
gpt4 key购买 nike

我有两个相关模型:ProductProductDescription。在 1 次提交操作中,用户可以插入具有多个描述的新 Product,具体取决于可用语言。我使用可写嵌套序列化器同时插入 ProductProductDescription 中。我通过重写 ProductDescriptionSerializer 类中的 create 函数来实现,它可以工作。但是,我一次只能插入 1 个 ProductDescription

然后我尝试使用这个answer一次创建多个模型实例。问题是它还会创建相同的 Product 两次,而不是使用新创建的 Product Id 插入下一个 ProductDescription

我的models.py:

class Product(models.Model, ProductStatus):
product_code = models.CharField(max_length=6)
color = models.ForeignKey(ColorParent, on_delete=models.SET_NULL, null=True)
collection = models.ForeignKey(ProductCollection, on_delete=models.SET_NULL, null=True)
video = models.URLField(verbose_name='Video URL', max_length=250, null=True, blank=True)
status = models.CharField(max_length=20, choices=ProductStatus.status, default=ProductStatus.active)


class ProductDescription(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
language = models.ForeignKey(Language, on_delete=models.CASCADE)
description = models.TextField(max_length=500, null=True, blank=True)

def __str__(self):
return '%s - %s' % (self.product, self.language)

我的serializers.py:

class CustomRelatedField(serializers.RelatedField):
def display_value(self, instance):
return instance

def to_representation(self, value):
return str(value)

def to_internal_value(self, data):
model = self.queryset.model
return model.objects.get(id=data)


class ProductSerializer(serializers.ModelSerializer):
collection = CustomRelatedField(queryset=ProductCollection.objects.all(), many=False)
color = CustomRelatedField(queryset=ColorParent.objects.all(), many=False)

class Meta:
model = Product
fields = ['id', 'product_code', 'collection', 'color', 'video', 'status']


class ProductDescriptionSerializer(serializers.ModelSerializer):
product = ProductSerializer()
language = CustomRelatedField(many=False, queryset=Language.objects.all())

class Meta:
model = ProductDescription
fields = ['id', 'product', 'language', 'description']

def to_representation(self, instance):
data = super().to_representation(instance)
if self.context['request'].method == 'GET':
data['product'] = instance.product.product_code
return data
return Serializer.to_representation(self, instance)

# The `.create()` method does not support writable nested fields by default.
def create(self, validated_data):
# create product data for Product model.
product_data = validated_data.pop('product')
product = Product.objects.create(**product_data)

# create ProductDescription and set product FK.
product_description = ProductDescription.objects.create(product=product, **validated_data)

# return ProductDescription instance.
return product_description

我的views.py:

class CreateListModelMixin(object):
def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
kwargs['many'] = True
return super(CreateListModelMixin, self).get_serializer(*args, **kwargs)


class ProductDescriptionView(CreateListModelMixin, viewsets.ModelViewSet):
permission_classes = [permissions.DjangoModelPermissions]
queryset = ProductDescription.objects.all()
serializer_class = ProductDescriptionSerializer
http_method_names = ['get', 'head', 'post', 'put', 'patch', 'delete']

我用来 POST 数据的 JSON 格式:

[
{
"product": {
"product_code": "BQ1080",
"collection": 5,
"color": 7,
"video": "https://www.youtube.com/watch?v=",
"status": "Continue"
},
"language": 1,
"description": "English description."
},
{
"product": {
"product_code": "BQ1080",
"collection": 5,
"color": 7,
"video": "https://www.youtube.com/watch?v=",
"status": "Continue"
},
"language": 2,
"description": "Vietnamese description."
}
]

它在产品列表中创建重复的产品:

[
{
"id": 26,
"product_code": "BQ1080",
"collection": 5,
"color": 7,
"video": "https://www.youtube.com/watch?v=",
"status": "Continue"
},
{
"id": 27,
"product_code": "BQ1080",
"collection": 5,
"color": 7,
"video": "https://www.youtube.com/watch?v=",
"status": "Continue"
}
]

ProductDescription 数据是正确的:

[
{
"id": 5,
"product": "BQ1080",
"language": "English",
"description": "English description."
},
{
"id": 6,
"product": "BQ1080",
"language": "Vietnam",
"description": "Vietnamese description."
}
]

最佳答案

为了避免重复产品,您可以使用 get_or_create()方法:

class ProductDescriptionSerializer(serializers.ModelSerializer):

...

def create(self, validated_data):
# create product data for Product model.
product_data = validated_data.pop('product')
product_code = product_data.pop("product_code")
product, _ = Product.objects.get_or_create(product_code=product_code, defaults=product_data)

# create ProductDescription and set product FK.
product_description = ProductDescription.objects.create(product=product, **validated_data)

# return ProductDescription instance.
return product_description

请注意,get_or_create 很容易出现竞争条件。因此,如果您同时收到两个相同的请求,您可能仍然有重复的产品。

关于python - 如何在 Django REST Framework 中创建多个模型实例而无需重复的可写嵌套序列化程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60110967/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com