使用 SlugRelatedField 创建和保存外键对象
Creating and saving foreign key objects using a SlugRelatedField
我刚开始使用 Django REST 框架,但在保存外键时遇到了问题。我有一个 Merchant
模型和一个 Phone
模型。 Phone
有一个指向 Merchant
的外键。在向 Merchant
发出 POST
请求时,我想为请求中提供的数字创建 Phone
对象。但是当我提供 phone 数字时,它给了我以下错误
Object with phone=0123456789 does not exist.
我只想让它自己创建 Phone
对象。以下是我使用的模型:
class Merchant(models.Model):
merchant_id = models.CharField(max_length=255)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
class Meta:
managed = True
db_table = 'merchant'
# Managers
objects = models.Manager()
active = managers.ActiveManager()
class Phone(models.Model):
phone = models.CharField(max_length=255)
merchant = models.ForeignKey('merchant.Merchant',
related_name='phones',
blank=True,
null=True)
class Meta:
managed = True
db_table = 'phone'
这是我正在使用的视图和序列化程序
class MerchantSerializer(serializers.ModelSerializer):
phones = serializers.SlugRelatedField(
many=True,
slug_field='phone',
queryset=primitives.Phone.objects.all())
class Meta:
model = Merchant
fields = (
'merchant_id',
'name',
'is_active',
'phones',
)
class MerchantViewSet(viewsets.ModelViewSet):
queryset = Merchant.active.all()
serializer_class = MerchantSerializer
这是我的请求正文:
{
"merchant_id": "emp011",
"name": "Abhinav",
"is_active": true,
"phones": [
"0123456789",
"9876543210"
]
}
这是回复:
400 错误请求
{"phones":["Object with phone=0123456789 does not exist."]}
您必须为对象 Phone 的 phone 字段指定一个值。如果您想创建 phone 对象而不指定字段 phone 的值,那么您必须启用 null 和空白字段。
phone = models.CharField(max_length=255,null=true,blank=true)
如果您仍然遇到问题,请确保 post 数据包含必填字段。您可以为此使用 ipdb。
The SlugRelatedField
由 Django REST framework 提供,与许多相关领域一样,旨在与已经存在的对象一起使用。由于您要引用已经存在的对象或需要创建的对象,因此您将无法按原样使用它。
您将需要一个自定义 SlugRelatedField
来在对象不存在时创建新对象。
class CreatableSlugRelatedField(serializers.SlugRelatedField):
def to_internal_value(self, data):
try:
return self.get_queryset().get_or_create(**{self.slug_field: data})[0]
except ObjectDoesNotExist:
self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
except (TypeError, ValueError):
self.fail('invalid')
class MerchantSerializer(serializers.ModelSerializer):
phones = CreatableSlugRelatedField(
many=True,
slug_field='phone',
queryset=primitives.Phone.objects.all()
)
class Meta:
model = Merchant
fields = (
'merchant_id',
'name',
'is_active',
'phones',
)
通过切换到 get_or_create
,phone 数字对象将被创建(如果尚不存在)。如果必须在模型上创建其他字段,您可能需要对此进行调整。
基于 Kevin 的回答,由于未使用 get_or_create
和 [0]
,IMO 变得更简洁了
class CreatableSlugRelatedField(serializers.SlugRelatedField):
def to_internal_value(self, data):
try:
return self.get_queryset().get(**{self.slug_field: data})
except ObjectDoesNotExist:
return self.get_queryset().create(**{self.slug_field: data}) # to create the object
except (TypeError, ValueError):
self.fail('invalid')
请注意,相关对象中唯一必填的字段应该是 slug 字段。
我刚开始使用 Django REST 框架,但在保存外键时遇到了问题。我有一个 Merchant
模型和一个 Phone
模型。 Phone
有一个指向 Merchant
的外键。在向 Merchant
发出 POST
请求时,我想为请求中提供的数字创建 Phone
对象。但是当我提供 phone 数字时,它给了我以下错误
Object with phone=0123456789 does not exist.
我只想让它自己创建 Phone
对象。以下是我使用的模型:
class Merchant(models.Model):
merchant_id = models.CharField(max_length=255)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
class Meta:
managed = True
db_table = 'merchant'
# Managers
objects = models.Manager()
active = managers.ActiveManager()
class Phone(models.Model):
phone = models.CharField(max_length=255)
merchant = models.ForeignKey('merchant.Merchant',
related_name='phones',
blank=True,
null=True)
class Meta:
managed = True
db_table = 'phone'
这是我正在使用的视图和序列化程序
class MerchantSerializer(serializers.ModelSerializer):
phones = serializers.SlugRelatedField(
many=True,
slug_field='phone',
queryset=primitives.Phone.objects.all())
class Meta:
model = Merchant
fields = (
'merchant_id',
'name',
'is_active',
'phones',
)
class MerchantViewSet(viewsets.ModelViewSet):
queryset = Merchant.active.all()
serializer_class = MerchantSerializer
这是我的请求正文:
{
"merchant_id": "emp011",
"name": "Abhinav",
"is_active": true,
"phones": [
"0123456789",
"9876543210"
]
}
这是回复:
400 错误请求
{"phones":["Object with phone=0123456789 does not exist."]}
您必须为对象 Phone 的 phone 字段指定一个值。如果您想创建 phone 对象而不指定字段 phone 的值,那么您必须启用 null 和空白字段。
phone = models.CharField(max_length=255,null=true,blank=true)
如果您仍然遇到问题,请确保 post 数据包含必填字段。您可以为此使用 ipdb。
The SlugRelatedField
由 Django REST framework 提供,与许多相关领域一样,旨在与已经存在的对象一起使用。由于您要引用已经存在的对象或需要创建的对象,因此您将无法按原样使用它。
您将需要一个自定义 SlugRelatedField
来在对象不存在时创建新对象。
class CreatableSlugRelatedField(serializers.SlugRelatedField):
def to_internal_value(self, data):
try:
return self.get_queryset().get_or_create(**{self.slug_field: data})[0]
except ObjectDoesNotExist:
self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
except (TypeError, ValueError):
self.fail('invalid')
class MerchantSerializer(serializers.ModelSerializer):
phones = CreatableSlugRelatedField(
many=True,
slug_field='phone',
queryset=primitives.Phone.objects.all()
)
class Meta:
model = Merchant
fields = (
'merchant_id',
'name',
'is_active',
'phones',
)
通过切换到 get_or_create
,phone 数字对象将被创建(如果尚不存在)。如果必须在模型上创建其他字段,您可能需要对此进行调整。
基于 Kevin 的回答,由于未使用 get_or_create
和 [0]
class CreatableSlugRelatedField(serializers.SlugRelatedField):
def to_internal_value(self, data):
try:
return self.get_queryset().get(**{self.slug_field: data})
except ObjectDoesNotExist:
return self.get_queryset().create(**{self.slug_field: data}) # to create the object
except (TypeError, ValueError):
self.fail('invalid')
请注意,相关对象中唯一必填的字段应该是 slug 字段。