DRF 3.0: UniqueTogetherValidator with a read-only field
django-rest-framework
Solution
This is a known issue that we are in the process of addressing within Django REST Framework. As of right now, there is a note in the documentation about UniqueTogtherValidator that says
Note: The `UniqueTogetherValidation` class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
This explains why you are seeing an error because the field is required, even though you are explicitly settings `read_only=True`. You may want to look into the `CurrentUserDefault` class, which may suit your needs while avoiding the issue with the `UniqueTogetherValidator`.
class ExampleSerializer(serializers.ModelSerializer):
user = UserSerializer(
read_only=True
default=serializers.CurrentUserDefault()
)
class Meta:
model = ExampleModel
This should do the same thing as your `perform_create` and `perform_update` hooks.
Problem
In process of upgrading to Django REST Framework 3.0 from 2.4.4 and I want to have a read-only user field, but this is failing because 'user' is being required by the UniqueTogetherValidator (I think) I have model (excuse typos, this is simplified and the code works fine IRL): ``` class ExampleModel(models.Model): some_attr = models.PositiveSmallIntegerField() other_attr = models.PositiveSmallIntegerField() user = models.ForeignKey(User) class Meta: unique_together = ('some_attr', 'other_attr', 'user') ``` Viewset: ``` class ExampleViewSet(viewsets.ModelViewSet): queryset = ExampleModel.objects.all() serializer_class = ExampleSerializer def perform_create(self, serializer): serializer.save(user=self.request.user) def perform_update(self, serializer): serializer.save(user=self.request.user) ``` Serializer: ``` class ExampleSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) class Meta: model = ExampleModel ``` Now, I keep getting errors saying: `{"user":["This field is required."]}`, which was not the case before. In a slightly different example with the same basic problem, I get the assertion error `May not set both 'read_only' and 'required'` even though I am not setting user as required. I receive the same error regardless if I add `required=False` for the user attribute in the serializer, or if I add user to the the excluded fields in the serializer's meta. When I use the handy new serializer printing, I see: ``` class Meta: validators = [UniqueTogetherValidator(queryset=ExampleModel.objects.all(), fields=('user', 'some_attr', 'other_attr'))] ``` which gets automatically added based on the model's unique_together. If I explicitly overwrite this and do not include 'user' in the fields for `UniqueTogetherValidator` then everything works as before. Is this an intended consequence of the 3.0 update? Seems to me that adding `request.user` in the `perform_create` / `perform_update` is very standard DRF procedure as demonstrated in the tutorial. I realize not having the new validation just means failing at the DB level instead, and the new validation probably gives better error messages, but Is there a solution other than to override the validation for every serializer where this is an issue? Thanks in advance for any help!