简体   繁体   中英

Django Rest Framework - Post Foreign Key

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": "xxx@gmail.com",
  "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!

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": "xxx@gmail.com",
  "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": "xxx@gmail.com",
  "birthday": "1991-05-28",
  "bio": "qudur",
  "points": 31
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM