Я использую 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
Проблема в том, что я не уверен, как создать поля для контактов по телефону и электронной почте, не отправляя первичный ключ (я бы хотел, чтобы он создавался автоматически). Я создал этот тест, чтобы попробовать ...
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')]}
Какой правильный способ настроить мой сериализатор для создания внешних ключей без указать идентификатор?
Изменить: Репозиторий GitHub:
https://github.com/chicommons/maps/tree/master/web