usermine12
usermine12

Reputation: 77

IntegrityError: UNIQUE constraint failed, how to catch and respond

I'm making a marketplace app with Django REST framework which I'm new to.

I wrote a test to test the unique together field. It works as I wanted it to, raising a UNIQUE constraint failed error when the fields author and target are not unique together, but my question is how should I handle this error so that my test would pass.

models.py

class Review(models.Model):
    FEEDBACK_CHOICES = [
        ('POSITIVE', 'positive'),
        ('NEUTRAL', 'neutral'),
        ('NEGATIVE', 'negative')
    ]

    feedback = models.CharField(
        max_length=8,
        choices=FEEDBACK_CHOICES,
        default='NEGATIVE'
    )
    review = models.TextField(max_length=200)
    target = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name='reviews',
        on_delete=models.CASCADE
    )
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name='given_reviews',
        on_delete=models.CASCADE
    )
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['created']
        unique_together = ['author', 'target']

serializers.py

class ReviewSerializer(serializers.ModelSerializer):
    target = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all()
    )
    author = serializers.ReadOnlyField(source='author.id')

    class Meta:
        model = Review
        fields = [
            'id',
            'feedback',
            'review',
            'target',
            'author',
            'created'
        ]

views.py

class ReviewViewSet(viewsets.ModelViewSet):
    queryset = Review.objects.all()
    serializer_class = ReviewSerializer

    permission_classes = [
        ReviewPermissions
    ]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

Upvotes: 0

Views: 1700

Answers (1)

user1600649
user1600649

Reputation:

This is described in the documentation:

If only the expected_exception and expected_message parameters are given, returns a context manager so that the code being tested can be written inline rather than as a function:

with self.assertRaisesMessage(ValueError, 'invalid literal for int()'):
    int('a')

But that is meant for tests on the model level.

If you use DRF's test client you should check for a response status other then 200 and override the exception handler in handle_exception or related methods of ApiView, so that you can determine the cause and provide data in the response that makes it testable. You then inspect the response of the client, in the same way as you would with Django's Test Client.

You can for example return a json response like this:

{
    success: false,
    code: INTEGRITY_UNIQUE_ERROR,
    message: this could contain details you could test for, like field names
}

Upvotes: 1

Related Questions