我知道这个问题已经被问过很多次了,但我仍然找不到正确的解决方案。假设我有如下模型
class Student(models.Model):
number = models.IntegerField()
department = models.ForeignKey(Department, on_delete=models.CASCADE)
class Meta:
constraints = [
models.UniqueConstraint(fields=['department', 'number'])
]
我的序列化程序如下所示。
class StudentModelSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ("number",)
在这个模型中,department
和number
是unique
,现在department是从传入的pk
中获取的网址。我处理独特错误的方式如下。
class StudentViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def perform_create(self, serializer):
department = Department.objects.get(pk=self.kwargs['pk'])
serializer.save(department=department)
def create(self, request, *args, **kwargs):
try:
return super().create(request, *args, **kwargs)
except IntegrityError as err:
if 'UNIQUE constraint' in err.message:
raise ValidationError({
'number': 'Number field should be unique.'
})
else:
raise IntegrityError(err)
如上所示,我调用了 super().create()
捕获异常,然后检查出现的 UNIQUE
消息,如果出现我再次引发验证错误,所以 rest framework 的异常处理程序
会处理它。如果不是我再次提出错误。
这种方法的问题是我正在检查消息 UNIQUE
的唯一错误,将来可能会改变。当然我可以将部门添加到 serializer context
和 validate
before save,但这可能会导致 race condition
,那么处理这种情况的最佳实践
是什么?
最佳答案
更好的方法是将异常的 pgcode 与 psycopg2 错误代码进行比较:
from psycopg2 import errorcodes
class StudentViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def perform_create(self, serializer):
department = Department.objects.get(pk=self.kwargs['pk'])
serializer.save(department=department)
def create(self, request, *args, **kwargs):
try:
return super().create(request, *args, **kwargs)
except IntegrityError as err:
if err.__cause__.pgcode == errorcodes.UNIQUE_VIOLATION and \
"number" in err.args[0]
raise ValidationError({
'number': 'Number field should be unique.'
})
raise
关于python - 处理唯一一起错误的最佳方法 - Django 2.2?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55528622/