简体   繁体   中英

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)

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
}

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