#python #django #django-models #django-rest-framework
#питон #джанго #django-модели #django-rest-фреймворк #python #django #django-rest-framework
Вопрос:
Я знаю, что этот вопрос задавался много раз, но я все еще не могу найти правильное решение., допустим, у меня есть модель, подобная follow
class Student(models.Model):
number = models.IntegerField()
department = models.ForeignKey(Department, on_delete=models.CASCADE)
class Meta:
constraints = [
models.UniqueConstraint(fields=['department', 'number'])
]
и мой сериализатор выглядит как follow.
class StudentModelSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ("number",)
В этой модели department
так number
и есть unique together
, теперь отдел извлекается из pk
переданного в URL. способ, которым я обрабатываю уникальную ошибку, выглядит следующим образом.
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's exception handler
обработайте это. если нет, я снова вызываю ошибку.
Проблема с этим подходом заключается в том, что я проверяю уникальную ошибку с сообщением, UNIQUE
которое может измениться в будущем., конечно, я могу добавить отдел в serializer context
и validate
перед сохранением, но это может привести к race condition
, так что же best practice
делать с подобным сценарием?
Комментарии:
1. можете ли вы показать конфигурацию URL?
2. Конечный URL-адрес должен быть таким
[POST] http://localhost/departments/{pk}/students
3. проверьте мой ответ ниже 🙂
Ответ №1:
Лучшим способом может быть сравнение 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