Hope someone can help me out here, I am trying to test a post method on an API, but the post method is not working as expected.
When I pass the payload to the post method, the points and de code fields are loaded but the shopper and card fields, which are both Foreing Keys, are not loaded and a null value is passed, as they are required fields I ended up getting an error.
I did check, and the values for self.shopper.pk and self.card.pk are correct.
MYCARDS_URL = reverse('mycards:mycards-list')
def test_create_mycards(self):
"""Test creating a mycards"""
payload = {
'shopper': self.shopper.pk,
'card': self.card.pk,
'points': 0,
'code': "code",
}
res = APIClient().post(MYCARDS_URL, payload)
I did check to see if was something related to my serializer, but it is all good as you can see:
class MycardsSerializer(serializers.ModelSerializer): """Serializer for cards."""
class Meta:
model = MyCards
fields = ['id', 'shopper', 'card', 'updated', 'created']
read_only_fields = ['id', 'created']
class MycardsDetailSerializer(MycardsSerializer): """Serializer for card detail view."""
class Meta(MycardsSerializer.Meta):
fields = MycardsSerializer.Meta.fields + [
'points', 'code']
Here is also my viewset which seems to be ok:
class MycardsViewSet(viewsets.ModelViewSet):
"""View for manage card APIs."""
serializer_class = serializers.MycardsDetailSerializer
queryset = MyCards.objects.all()
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Retrieve cards for authenticated user."""
shoppers = list(Shopper.objects.all().filter(
user=self.request.user).values_list('id'))
return self.queryset.filter(shopper=shoppers[0]).order_by('-id')
def get_serializer_class(self):
"""Return the serrializer class for request."""
if self.action == 'list':
return serializers.MycardsSerializer
return self.serializer_class
def perform_create(self, serializer):
"""Create a new recipe."""
serializer.save()
I have printed the serializer.dict from inside the perform_create method and got the following:
{'_args': (), '_kwargs': {'data': <QueryDict: {'shopper': ['5'], 'card': ['15'], 'points': ['0'], 'code': ['code']}>, 'context': {'request': <rest_framework.request.Request: POST '/api/mycards/'>, 'format': None, 'view': <mycards.views.MycardsViewSet object at 0x7f7ebd4ce400>}}, 'instance': None, 'initial_data': <QueryDict: {'shopper': ['5'], 'card': ['15'], 'points': ['0'], 'code': ['code']}>, 'partial': False, '_context': {'request': <rest_framework.request.Request: POST '/api/mycards/'>, 'format': None, 'view': <mycards.views.MycardsViewSet object at 0x7f7ebd4ce400>}, '_creation_counter': 198, 'read_only': False, 'write_only': False, 'required': True, 'default': <class 'rest_framework.fields.empty'>, 'source': None, 'initial': None, 'label': None, 'help_text': None, 'style': {}, 'allow_null': False, 'field_name': None, 'parent': None, 'error_messages': {'required': 'This field is required.', 'null': 'This field may not be null.', 'invalid': 'Invalid data. Expected a dictionary, but got {datatype}.'}, 'url_field_name': 'url', 'fields': {'id': IntegerField(label='ID', read_only=True), 'shopper': PrimaryKeyRelatedField(read_only=True), 'card': PrimaryKeyRelatedField(read_only=True), 'updated': DateTimeField(read_only=True), 'created': DateTimeField(read_only=True), 'points': IntegerField(max_value=2147483647, min_value=-2147483648, required=False), 'code': CharField(allow_blank=True, allow_null=True, max_length=6, required=False)}, '_validators': [], '_validated_data': OrderedDict([('points', 0), ('code', 'code')]), '_errors': {}}
here I could notice 2 things, first that the values are passed to the serializer as noted on the line below:
'shopper': ['5'], 'card': ['15'], 'points': ['0'], 'code': ['code']
but at the end of the serializer.dict I could find the following message:
'_validated_data': OrderedDict([('points', 0), ('code', 'code')]), '_errors':
points and code are going through, but the shopper and the card are not, I just have no idea why is it happening :/