I am trying to develop a REST API with django-rest-framework for updating a django model.
I want to unit test it with the following unit test
from rest_framework.test import APITestCase
class PatchInvestmentTest(APITestCase):
def test_repartition(self):
investment = Investment.objects.create()
sponsor1 = Investment.objects.create(InvestmentSponsor, name='A')
sponsor2 = Investment.objects.create(InvestmentSponsor, name='B')
url = reverse('investments:investments-detail', args=[investment.id])
data = {
'sponsorships': [
{'sponsor': sponsor1.id, 'percentage': 80},
{'sponsor': sponsor2.id, 'percentage': 10},
]
}
print("> data", data)
response = self.client.patch(url, data=data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(1, Investment.objects.count())
investment = Investment.objects.all()[0]
# It fails below : no investments are created
self.assertEqual(len(investment.sponsorships()), 2)
The model can be summed up with
class Investment(models.Model):
# ... a few fields
def sponsorships(self):
return self.investmentsponsorship_set.all().order_by('sponsor__ordering', 'sponsor__name')
class InvestmentSponsor(models.Model):
name = models.CharField(max_length=200, verbose_name=_('name'))
ordering = models.IntegerField(default=0)
class Meta:
ordering = ('ordering', 'name', )
class InvestmentSponsorship(models.Model):
sponsor = models.ForeignKey(InvestmentSponsor)
investment = models.ForeignKey(Investment)
percentage = models.DecimalField(max_digits=5, decimal_places=2)
The api is using rest-framework base classes
class InvestmentViewSet(viewsets.ModelViewSet):
model = Investment
def get_serializer_class(self):
serializers_class_map = {
'default': InvestmentSerializer,
'partial_update': PartialUpdateInvestmentSerializer,
}
return serializers_class_map.get(self.action, serializers_class_map['default'])
def perform_update(self, serializer):
serializer.save()
Then I expect to get and handle the "sponsorhips" data in the serializers
class InvestmentSponsorshipSerializer(serializers.ModelSerializer):
class Meta:
model = models.InvestmentSponsorship
fields = ('sponsor', 'percentage', )
class PartialUpdateInvestmentSerializer(serializers.ModelSerializer):
sponsorships = InvestmentSponsorshipSerializer(many=True)
class Meta:
model = models.Investment
fields = (
'id', '... others', 'sponsorships',
)
def validate_sponsorships(self, value):
print("validate_sponsorships", value)
return value
def update(self, instance, validated_data):
"""update only fields in data"""
data = validated_data.copy()
print("*** DATA", validated_data)
instance.save()
return instance
The problem is that the data I received from the serializer is empty
> data {'sponsorships': [{'sponsor': 1, 'percentage': 80}, {'sponsor': 2, 'percentage': 10}]}
validate_sponsorships []
*** DATA {'sponsorships': []}
This seems to occur only when unit testing. It seems to work from the dango-rest-framework admin.
I've tried to investigate why I don't received the data as validated_data in the update with no success yet.
Any idea?
related_name='sponsorships'
forinvestment
foreign key onInvestmentSponsorship
model ? (you would have to get rid of thesponsorship
method onInvestment
). If that works, you can had ordering onInvestmentSponsorship
Meta
. – Michael Rigoni