在 Django 中,如何创建一个序列化程序来为我的模型成员自动生成主键?
In Django, how do I create a serializer that will auto-generate a primary key for a member of my model?
我正在使用 Django 3、Django REST 框架和 Python 3.7。我有以下型号。请注意,第二个依赖于第一个 ...
class ContactMethod(models.Model):
class ContactTypes(models.TextChoices):
EMAIL = 'EMAIL', _('Email')
PHONE = 'PHONE', _('Phone')
type = models.CharField(
null=False,
max_length=5,
choices=ContactTypes.choices,
)
phone = PhoneNumberField(null=True)
email = models.EmailField(null=True)
class Meta:
unique_together = ('phone', 'email',)
...
class Coop(models.Model):
objects = CoopManager()
name = models.CharField(max_length=250, null=False)
types = models.ManyToManyField(CoopType)
addresses = models.ManyToManyField(Address)
enabled = models.BooleanField(default=True, null=False)
phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
web_site = models.TextField()
我想提交一些 JSON 来创建我的模型,所以我创建了以下两个序列化程序来帮助我 ...
class ContactMethodSerializer(serializers.ModelSerializer):
class Meta:
model = ContactMethod
fields = ['type', 'phone', 'email']
def create(self, validated_data):
contact_method = ContactMethod.objects.create(**validated_data)
return contact_method
def to_internal_value(self, data):
if type(data) == dict:
contatcmethod, created = CoopType.objects.create(**data)
# Replace the dict with the ID of the newly obtained object
data = contactmethod.pk
return super().to_internal_value(data)
...
class CoopSerializer(serializers.ModelSerializer):
types = CoopTypeSerializer(many=True)
addresses = AddressTypeField(many=True)
class Meta:
model = Coop
fields = ['id', 'name', 'types', 'addresses', 'phone', 'enabled', 'email', 'web_site']
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['types'] = CoopTypeSerializer(instance.types.all(), many=True).data
rep['addresses'] = AddressSerializer(instance.addresses.all(), many=True).data
return rep
def create(self, validated_data):
#"""
#Create and return a new `Snippet` instance, given the validated data.
#"""
coop_types = validated_data.pop('types', {})
instance = super().create(validated_data)
for item in coop_types:
coop_type, _ = CoopType.objects.get_or_create(name=item['name'])
instance.types.add(coop_type)
return instance
问题是,我不确定如何在不提交主键的情况下创建我的 phone 和电子邮件联系人字段(我希望自动生成)。我创建此测试是为了尝试...
def test_coop_create(self):
""" Test coop serizlizer model """
name = "Test 8899"
coop_type_name = "Library"
street = "222 W. Merchandise Mart Plaza, Suite 1212"
city = "Chicago"
postal_code = "60654"
enabled = True
postal_code = "60654"
email = EmailContactMethodFactory()
phone = PhoneContactMethodFactory()
web_site = "http://www.1871.com"
state = StateFactory()
serializer_data = {
"name": name,
"types": [
{"name": coop_type_name}
],
"addresses": [{
"formatted": street,
"locality": {
"name": city,
"postal_code": postal_code,
"state_id": state.id
}
}],
"enabled": enabled,
"phone": {
"phone": phone
},
"email": {
"email": email
},
"web_site": web_site
}
serializer = CoopSerializer(data=serializer_data)
serializer.is_valid()
assert serializer.is_valid(), serializer.errors
coop = serializer.save()
assert coop.name == name
type_count = 0
for coop_type in coop.types.all():
assert coop_type.name == coop_type_name
type_count = type_count + 1
assert type_count == 1
assert coop.addresses.first().locality.name == city
assert coop.addresses.first().locality.postal_code == postal_code
assert coop.addresses.first().locality.state.id == state.id
assert coop.enabled == enabled
assert coop.phone.phone == phone
assert coop.email.email == email
assert coop.web_site == web_site
但它导致以下错误
AssertionError: {'phone': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'email': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')]}
设置序列化程序以创建外键而无需指定 ID 的正确方法是什么?
编辑: GitHub 回购:
https://github.com/chicommons/maps/tree/master/web
开箱即用,rest-framework 使用主键序列化关系(phone
、email
)。
Any relationships such as foreign keys on the model will be mapped to PrimaryKeyRelatedField. Reverse relationships are not included by default unless explicitly included as specified in the serializer relations documentation.
来源:https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
您通常会创建 ContactMethod
个对象,一个用于 name
(例如 id=1),第二个用于 email
(id=2),然后再创建 [=17] =] 然后将他们的 ID 包含在我们的有效负载中。所以它看起来像
{
// ...
"phone": 1,
"email": 2,
// ...
}
在您的情况下,您需要在创建 Coop
时创建 ContactMethod
。您需要更改 CoopSerializer
以接受由 email
字段中的 ContactMethodEmailSerializer
和 phone
字段中的 ContactMethodPhoneSerializer
序列化的有效载荷。
class ContactMethodPhoneSerializer(serializers.ModelSerializer):
class Meta:
model = ContactMethod
fields = ['type', 'phone']
read_only_fields = ['type']
extra_kwargs = {'type': {'default': 'PHONE'}}
class ContactMethodEmailSerializer(serializers.ModelSerializer):
class Meta:
model = ContactMethod
fields = ['type', 'email']
read_only_fields = ['type']
extra_kwargs = {'type': {'default': 'EMAIL'}}
class CoopSerializer(serializers.ModelSerializer):
types = CoopTypeSerializer(many=True)
addresses = AddressTypeField(many=True)
phone = ContactMethodPhoneSerializer()
email = ContactMethodEmailSerializer()
使用此序列化程序,您的测试负载应该被接受。
在 CoopSerializer.create
方法中,您需要处理 ContactMethod
的创建,类似于您对 CoopType
所做的,您可以按照文档中的示例进行操作:
https://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations
我正在使用 Django 3、Django REST 框架和 Python 3.7。我有以下型号。请注意,第二个依赖于第一个 ...
class ContactMethod(models.Model):
class ContactTypes(models.TextChoices):
EMAIL = 'EMAIL', _('Email')
PHONE = 'PHONE', _('Phone')
type = models.CharField(
null=False,
max_length=5,
choices=ContactTypes.choices,
)
phone = PhoneNumberField(null=True)
email = models.EmailField(null=True)
class Meta:
unique_together = ('phone', 'email',)
...
class Coop(models.Model):
objects = CoopManager()
name = models.CharField(max_length=250, null=False)
types = models.ManyToManyField(CoopType)
addresses = models.ManyToManyField(Address)
enabled = models.BooleanField(default=True, null=False)
phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
web_site = models.TextField()
我想提交一些 JSON 来创建我的模型,所以我创建了以下两个序列化程序来帮助我 ...
class ContactMethodSerializer(serializers.ModelSerializer):
class Meta:
model = ContactMethod
fields = ['type', 'phone', 'email']
def create(self, validated_data):
contact_method = ContactMethod.objects.create(**validated_data)
return contact_method
def to_internal_value(self, data):
if type(data) == dict:
contatcmethod, created = CoopType.objects.create(**data)
# Replace the dict with the ID of the newly obtained object
data = contactmethod.pk
return super().to_internal_value(data)
...
class CoopSerializer(serializers.ModelSerializer):
types = CoopTypeSerializer(many=True)
addresses = AddressTypeField(many=True)
class Meta:
model = Coop
fields = ['id', 'name', 'types', 'addresses', 'phone', 'enabled', 'email', 'web_site']
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['types'] = CoopTypeSerializer(instance.types.all(), many=True).data
rep['addresses'] = AddressSerializer(instance.addresses.all(), many=True).data
return rep
def create(self, validated_data):
#"""
#Create and return a new `Snippet` instance, given the validated data.
#"""
coop_types = validated_data.pop('types', {})
instance = super().create(validated_data)
for item in coop_types:
coop_type, _ = CoopType.objects.get_or_create(name=item['name'])
instance.types.add(coop_type)
return instance
问题是,我不确定如何在不提交主键的情况下创建我的 phone 和电子邮件联系人字段(我希望自动生成)。我创建此测试是为了尝试...
def test_coop_create(self):
""" Test coop serizlizer model """
name = "Test 8899"
coop_type_name = "Library"
street = "222 W. Merchandise Mart Plaza, Suite 1212"
city = "Chicago"
postal_code = "60654"
enabled = True
postal_code = "60654"
email = EmailContactMethodFactory()
phone = PhoneContactMethodFactory()
web_site = "http://www.1871.com"
state = StateFactory()
serializer_data = {
"name": name,
"types": [
{"name": coop_type_name}
],
"addresses": [{
"formatted": street,
"locality": {
"name": city,
"postal_code": postal_code,
"state_id": state.id
}
}],
"enabled": enabled,
"phone": {
"phone": phone
},
"email": {
"email": email
},
"web_site": web_site
}
serializer = CoopSerializer(data=serializer_data)
serializer.is_valid()
assert serializer.is_valid(), serializer.errors
coop = serializer.save()
assert coop.name == name
type_count = 0
for coop_type in coop.types.all():
assert coop_type.name == coop_type_name
type_count = type_count + 1
assert type_count == 1
assert coop.addresses.first().locality.name == city
assert coop.addresses.first().locality.postal_code == postal_code
assert coop.addresses.first().locality.state.id == state.id
assert coop.enabled == enabled
assert coop.phone.phone == phone
assert coop.email.email == email
assert coop.web_site == web_site
但它导致以下错误
AssertionError: {'phone': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'email': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')]}
设置序列化程序以创建外键而无需指定 ID 的正确方法是什么?
编辑: GitHub 回购:
https://github.com/chicommons/maps/tree/master/web
开箱即用,rest-framework 使用主键序列化关系(phone
、email
)。
Any relationships such as foreign keys on the model will be mapped to PrimaryKeyRelatedField. Reverse relationships are not included by default unless explicitly included as specified in the serializer relations documentation.
来源:https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
您通常会创建 ContactMethod
个对象,一个用于 name
(例如 id=1),第二个用于 email
(id=2),然后再创建 [=17] =] 然后将他们的 ID 包含在我们的有效负载中。所以它看起来像
{
// ...
"phone": 1,
"email": 2,
// ...
}
在您的情况下,您需要在创建 Coop
时创建 ContactMethod
。您需要更改 CoopSerializer
以接受由 email
字段中的 ContactMethodEmailSerializer
和 phone
字段中的 ContactMethodPhoneSerializer
序列化的有效载荷。
class ContactMethodPhoneSerializer(serializers.ModelSerializer):
class Meta:
model = ContactMethod
fields = ['type', 'phone']
read_only_fields = ['type']
extra_kwargs = {'type': {'default': 'PHONE'}}
class ContactMethodEmailSerializer(serializers.ModelSerializer):
class Meta:
model = ContactMethod
fields = ['type', 'email']
read_only_fields = ['type']
extra_kwargs = {'type': {'default': 'EMAIL'}}
class CoopSerializer(serializers.ModelSerializer):
types = CoopTypeSerializer(many=True)
addresses = AddressTypeField(many=True)
phone = ContactMethodPhoneSerializer()
email = ContactMethodEmailSerializer()
使用此序列化程序,您的测试负载应该被接受。
在 CoopSerializer.create
方法中,您需要处理 ContactMethod
的创建,类似于您对 CoopType
所做的,您可以按照文档中的示例进行操作:
https://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations