Consider:
class CouponSerializer(serializers.ModelSerializer):
courses = serializers.PrimaryKeyRelatedField(
many=True, read_only=True)
class Meta:
model = Coupon
exclude = ['users']
If I remove read_only=True
, I get the error:
AssertionError: Relational field must provide a `queryset` argument, override `get_queryset`, or set read_only=`True`.
The documentation states:
The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True
What is the logic underlying this requirement? Why is there no such requirement for StringRelatedField
?
CodePudding user response:
Django Rest Framework has to know which queryset to look in for if the number the user sends in the request is valid.
Let's say a user sends a POST request to your view that uses this serializer. With a payload like this:
{
"courses": [1, 2, 3]
}
So, we want to create an instance of Coupon
with the field courses
to be populated with the instances of Course
with id 1, 2 and 3.
DRF will validate this request to make sure that the primary keys 1, 2 and 3 exists in the model Course
. If we don't add queryset = Course.objects.all()
then DRF doesn't know which model to look in.
The reason you don't have to add to StringRelatedField
is because that sort of field is read-only by default.
Edit:
If you use read_only=True
, then DRF will check in the model on the same field name the you have defined on the serializer. In you example Serializer you have named the field courses
, so DRF will check the model for a field named courses
and it know's it's a many-to-many field so it will fetch all primary keys from that.
You might ask yourself why DRF don't do the same thing on write. That is use the field name from the serializer to find out what model the field is referring to in the model. I don't have a good answer for this however.
CodePudding user response:
you need to add ready_only if you just will use this serializer to view data or using queryset argument if you want to save data, this let the serializer validate data before saving it to the database
example
class CouponSerializer(serializers.ModelSerializer):
courses = serializers.PrimaryKeyRelatedField(
many=True, queryset = Course.objects.all() )
class Meta:
model = Coupon
exclude = ['users']
this when validating data if not courses in your course list will raise error