Given the following contrived example, how can I POST to a URL with an ID in path and have it resolve the model instance instead of including the model instance in the POST body itself?
urls.py
path("api/schools/<int:pk>/student/", views.CreateStudentView.as_view(), name="createStudent")
models.py
class School(models.Model):
name = models.CharField(default="", max_length=128)
address = models.CharField(default="", max_length=128)
mascot = models.CharField(default="", max_length=128)
class StudentModel(models.Model):
first_name = models.CharField(default="", max_length=128)
last_name = models.CharField(default="", max_length=128)
notes = models.CharField(default="", max_length=512)
school = models.ForeignKey(School, on_delete=models.CASCADE)
serializers.py
class CreateStudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ("first_name", "last_name")
views.py
class CreateStudentView(generics.CreateAPIView):
serializer_class = CreateStudentSerializer
queryset = Student.objects.all()
I want to be able to POST just the new student's first name and last name to the URL to create a new student in my database. However, because I don't provide a School object in the body of my POST I get an error. I was hoping it would be possible for my code to resolve which school I want to add the student to because the URL contains the ID.
I get an error when I POST the following body to /api/schools/1/student/. The school with an ID of 1 does exist in the database.
{
"first_name": "John",
"last_name": "Smith"
}
IntegrityError at /api/schools/1/student/
NOT NULL constraint failed: students_school.school_id
The easiest way to do this is by overriding the create method of your
CreateStudentView. URL parameters are stored inself.kwargs, so you can retrieve it from there, and inject it into your serializer:Credits to this article, where you can read more about why this works.