mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
ModelSerializer.create() to handle many to many by default
This commit is contained in:
parent
9fdb2280d1
commit
106362b437
|
@ -24,7 +24,10 @@ class RelatedField(Field):
|
||||||
# We override this method in order to automagically create
|
# We override this method in order to automagically create
|
||||||
# `ManyRelation` classes instead when `many=True` is set.
|
# `ManyRelation` classes instead when `many=True` is set.
|
||||||
if kwargs.pop('many', False):
|
if kwargs.pop('many', False):
|
||||||
return ManyRelation(child_relation=cls(*args, **kwargs))
|
return ManyRelation(
|
||||||
|
child_relation=cls(*args, **kwargs),
|
||||||
|
read_only=kwargs.get('read_only', False)
|
||||||
|
)
|
||||||
return super(RelatedField, cls).__new__(cls, *args, **kwargs)
|
return super(RelatedField, cls).__new__(cls, *args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|
|
@ -344,7 +344,25 @@ class ModelSerializer(Serializer):
|
||||||
|
|
||||||
def create(self, attrs):
|
def create(self, attrs):
|
||||||
ModelClass = self.Meta.model
|
ModelClass = self.Meta.model
|
||||||
return ModelClass.objects.create(**attrs)
|
|
||||||
|
# Remove many-to-many relationships from attrs.
|
||||||
|
# They are not valid arguments to the default `.create()` method,
|
||||||
|
# as they require that the instance has already been saved.
|
||||||
|
info = model_meta.get_field_info(ModelClass)
|
||||||
|
many_to_many = {}
|
||||||
|
for key, relation_info in info.relations.items():
|
||||||
|
if relation_info.to_many and (key in attrs):
|
||||||
|
many_to_many[key] = attrs.pop(key)
|
||||||
|
|
||||||
|
instance = ModelClass.objects.create(**attrs)
|
||||||
|
|
||||||
|
# Save many to many relationships after the instance is created.
|
||||||
|
if many_to_many:
|
||||||
|
for key, value in many_to_many.items():
|
||||||
|
setattr(instance, key, value)
|
||||||
|
instance.save()
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
def update(self, obj, attrs):
|
def update(self, obj, attrs):
|
||||||
for attr, value in attrs.items():
|
for attr, value in attrs.items():
|
||||||
|
|
|
@ -360,7 +360,7 @@ class TestIntegration(TestCase):
|
||||||
|
|
||||||
self.serializer_cls = TestSerializer
|
self.serializer_cls = TestSerializer
|
||||||
|
|
||||||
def test_pk_relationship_representations(self):
|
def test_pk_retrival(self):
|
||||||
serializer = self.serializer_cls(self.instance)
|
serializer = self.serializer_cls(self.instance)
|
||||||
expected = {
|
expected = {
|
||||||
'id': self.instance.pk,
|
'id': self.instance.pk,
|
||||||
|
@ -370,3 +370,46 @@ class TestIntegration(TestCase):
|
||||||
'through': []
|
'through': []
|
||||||
}
|
}
|
||||||
self.assertEqual(serializer.data, expected)
|
self.assertEqual(serializer.data, expected)
|
||||||
|
|
||||||
|
def test_pk_create(self):
|
||||||
|
new_foreign_key = ForeignKeyTargetModel.objects.create(
|
||||||
|
name='foreign_key'
|
||||||
|
)
|
||||||
|
new_one_to_one = OneToOneTargetModel.objects.create(
|
||||||
|
name='one_to_one'
|
||||||
|
)
|
||||||
|
new_many_to_many = [
|
||||||
|
ManyToManyTargetModel.objects.create(
|
||||||
|
name='new many_to_many (%d)' % idx
|
||||||
|
) for idx in range(3)
|
||||||
|
]
|
||||||
|
data = {
|
||||||
|
'foreign_key': new_foreign_key.pk,
|
||||||
|
'one_to_one': new_one_to_one.pk,
|
||||||
|
'many_to_many': [item.pk for item in new_many_to_many],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serializer should validate okay.
|
||||||
|
serializer = self.serializer_cls(data=data)
|
||||||
|
assert serializer.is_valid()
|
||||||
|
|
||||||
|
# Creating the instance, relationship attributes should be set.
|
||||||
|
instance = serializer.save()
|
||||||
|
assert instance.foreign_key.pk == new_foreign_key.pk
|
||||||
|
assert instance.one_to_one.pk == new_one_to_one.pk
|
||||||
|
assert [
|
||||||
|
item.pk for item in instance.many_to_many.all()
|
||||||
|
] == [
|
||||||
|
item.pk for item in new_many_to_many
|
||||||
|
]
|
||||||
|
assert list(instance.through.all()) == []
|
||||||
|
|
||||||
|
# Representation should be correct.
|
||||||
|
expected = {
|
||||||
|
'id': instance.pk,
|
||||||
|
'foreign_key': new_foreign_key.pk,
|
||||||
|
'one_to_one': new_one_to_one.pk,
|
||||||
|
'many_to_many': [item.pk for item in new_many_to_many],
|
||||||
|
'through': []
|
||||||
|
}
|
||||||
|
self.assertEqual(serializer.data, expected)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user