Velvet Star Monitor

Standout celebrity highlights with iconic style.

general

Django Rest Framework - Post Foreign Key

Writer Olivia Zamora

I am new to Django Rest Framework and checked some tutorials. Now I am trying to create my own structure which is like following. I want to create a user which is OK, then create a profile seperately.

models.py

class User(models.Model): name = models.CharField(max_length=32) surname = models.CharField(max_length=32) facebook_id = models.TextField(null=True) is_sms_verified = models.BooleanField(default=False) created = models.DateTimeField(default=timezone.now) updated = models.DateTimeField(default=timezone.now) status = models.BooleanField(default=1) def __str__(self): return self.name+" "+self.surname
class Profile(models.Model): user = models.ForeignKey('User',on_delete=models.CASCADE) email = models.CharField(max_length=32) birthday = models.DateField(null=True) bio = models.TextField(null=True) points = models.IntegerField(default=0) created = models.DateTimeField(default=timezone.now) updated = models.DateTimeField(default=timezone.now) def __str__(self): return self.user.name+ " " + self.user.surname

serializers.py

class UserSerializer(serializers.ModelSerializer): class Meta: model=User fields = ('id','name','surname','facebook_id','is_sms_verified',) read_only_fields = ('created','updated')
class ProfileSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) class Meta: model=Profile fields=('id','user','email','birthday','bio','points') read_only_fields = ('created','updated')

views.py

@api_view(['POST'])
def profile_create(request): serializer = ProfileSerializer(data=request.data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, status = status.HTTP_201_CREATED) return JsonResponse(serializer.errors , status= status.HTTP_400_BAD_REQUEST)

data I'm trying to post

{ "user_id": { "id": 2 }, "email": "", "birthday": "1991-05-28", "bio": "qudur", "points": 31
}

The error I get;

NOT NULL constraint failed: core_profile.user_id

Where am I doing wrong? Thanks!

2 Answers

Your ProfileSerializer has user as readonly. So you need to change that. I would suggest doing it like this

class ProfileSerializer(serializers.ModelSerializer): class Meta: model=Profile fields=('id','user','email','birthday','gender','bio','points') read_only_fields = ('created','updated') def to_representation(self, instance): self.fields['user'] = UserSerializer(read_only=True) return super(ProfileSerializer, self).to_representation(instance)

If you do it this you could provide your user as plain id for POST

{ "user": 2, "email": "", "birthday": "1991-05-28", "bio": "qudur", "points": 31
}

And when you will read data it will look like this

{ "user": { "id": 2, "name": "Name", "surname": "Surname", ... }, "email": "", "birthday": "1991-05-28", "bio": "qudur", "points": 31
}
3

I've noticed Super() throws an error the way it's mentioned above in the awnser:

return super(ProfileSerializer,self).to_representation(instance)

Error: Type error, object must be an instance or subtype of type

Try the Following:

Models.py

class Program(models.Model): name = models.CharField(max_length=225) cost = models.IntegerField(default=0) description = models.TextField(default="", max_length=555)
class UserProgram(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) program = models.ForeignKey(Program, on_delete=models.CASCADE, related_name="program")

Serializers.py

class ProgramSerializers(serializers.ModelSerializer): class Meta: model = Program fields = "__all__"
class UserProgramSerializers(serializers.ModelSerializer): class Meta: model = UserProgram fields = "__all__" #IMPORTANT PART def to_representation(self, instance): response = super().to_representation(instance) response['program'] = ProgramSerializers(instance.program).data return response

Views.py

class UserProgramViewset(viewsets.ModelViewSet): permission_classes = [ permissions.IsAuthenticated ] serializer_class = UserProgramSerializers def get_queryset(self): return UserProgram.objects.filter(user=self.request.user) def perform_create(self, serializer): serializer.save(user=self.request.user)

When you call the GET request the following should be the output:GET Request Output

When you call the POST request you only need to pass the programID and not the whole JSON dictionary!

Hope this helped.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy