Published 4 March, 2019;
last updated on 23 April, 2021.
As part of a project I’m working on, I’m refactoring two nearly identical models (create.Event
and delete.Event
) into one (generic.Event
).
Doing this requites a handful of migrations to:
- create the table for
generic.Event
; - move the data from
create.Event
intogeneric.Event
and delete thecreate.Event
table; and - move the data from
delete.Event
intogeneric.Event
and delete thedelete.Event
table.
Migrations two and three call this function to move data between models:
from django.forms.models import model_to_dict
def move_events(source_model, dest_model):
for source in source_model.objects.all():
source_fields = model_to_dict(source)
del source_fields['id']
dest = dest_model()
for attr, value in source_fields.items():
setattr(dest, attr, value)
dest.save()
This works perfectly well … until I introduce real-world data and a unique event_id
field into my models. 😢
django.db.utils.IntegrityError: duplicate key value violates unique constraint "generic_event_id_key"
DETAIL: Key (event_id)=(the-duplicate-key) already exists.
Taking a pythonic “easier to ask for forgiveness than permission” approach, my first attempt at this was to wrap the call to save in a try … except block:
from django.db.utils import IntegrityError
try:
dest.save()
except IntegrityError as err:
print("Ignoring unhandled integrity error:")
print(err)
I naively deployed this fix expecting my problems to vanish, but the exceptions persisted. 😭
I was now getting TransactionManagementError
s.
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
After some digging, reading, and thinking, I realised that the cause of the IntegrityError
isn’t Python—it’s Postgres. Handling the error in Python is suppressing an error about a failed transaction, but the transaction is still failed.
The Django docs give a clue about what’s happening here:
Inside a transaction, when a call to a PostgreSQL cursor raises an exception (typically
IntegrityError
), all subsequent SQL in the same transaction will fail with the error “current transaction is aborted, queries ignored until end of transaction block”. While simple use ofsave()
is unlikely to raise an exception in PostgreSQL, there are more advanced usage patterns which might, such as saving objects with unique fields, saving using the force_insert/force_update flag, or invoking custom SQL.
In order to stop IntegrityError
s in your migrations, you need to “look before you leap” to stop the cause of them in the first place. For me, that meant something like the following:
def move_events(source_model, dest_model):
for source in source_model.objects.all():
source_fields = model_to_dict(source)
del source_fields['id']
# Ignore records with pre-existing event IDs.
event_id = source_fields['event_id']
if dest_model.objects.filter(event_id=event_id).exists():
print("Discarding record with duplicate event ID.")
pprint(source_fields)
continue
dest = dest_model()
for attr, value in source_fields.items():
setattr(dest, attr, value)
dest.save()
Learn how to fix integrity errors or not null constraint failed in Django. You can easily fix this error just avoid 2 simple mistakes.
I’m a full-time freelance contractor and available for hire.
My Expertise:
— Web Design,
— Web Development
— WordPress
— Python
— Graphic Design
For business queries:
wpcodersclub@gmail.com
Please subscribe to my channel for more amazing tuts.
Thanks for watching
Top comments (0)
For further actions, you may consider blocking this person and/or reporting abuse
Why You Need to Study Javascript Fundamentals
The harsh reality for JS Developers: If you don’t study the fundamentals, you’ll be just another “Coder”. Top learnings on how to get to the mid/senior level faster as a JavaScript developer by Dragos Nedelcu.
Read next
Automating Content Creation with Python: Obtaining Clips from Twitch
Vinicius Koji Enari — Jan 25
Build Your First Port Scanner using Python
Scofield Idehen — Feb 4
How to get Wallet Addresses from Comment section of a Tweet
Ycrypto-3 — Jan 2
Include ChatGPT on your WordPress website
Thomas Hansen — Jan 25
Django вызывает некоторые собственные исключения, а также стандартные исключения Python.
Исключения ядра Django¶
Классы исключений ядра Django определены в django.core.exceptions
.
AppRegistryNotReady
¶
-
exception
AppRegistryNotReady
[исходный код]¶ -
Это исключение возникает при попытке использовать модели до завершения процедуры app loading process, которая инициализирует ORM.
EmptyResultSet
¶
-
exception
EmptyResultSet
[исходный код]¶ -
EmptyResultSet
может возникнуть во время генерации запроса, если запрос не вернет никаких результатов. Большинство проектов Django не столкнутся с этим исключением, но оно может быть полезно для реализации пользовательских поисков и выражений.
FieldDoesNotExist
¶
-
exception
FieldDoesNotExist
[исходный код]¶ -
Исключение
FieldDoesNotExist
вызывается методом_meta.get_field()
модели, когда запрашиваемое поле не существует ни в модели, ни в родителях модели.
SuspiciousOperation
¶
-
exception
SuspiciousOperation
[исходный код]¶ -
Исключение
SuspiciousOperation
возникает, когда пользователь выполнил операцию, которую следует считать подозрительной с точки зрения безопасности, например, подделка куки сеанса. ПодклассыSuspiciousOperation
включают:DisallowedHost
DisallowedModelAdminLookup
DisallowedModelAdminToField
DisallowedRedirect
InvalidSessionKey
RequestDataTooBig
SuspiciousFileOperation
SuspiciousMultipartForm
SuspiciousSession
TooManyFieldsSent
Если исключение
SuspiciousOperation
достигает уровня обработчика ASGI/WSGI, оно регистрируется на уровнеError
и приводит к появлениюHttpResponseBadRequest
. Дополнительную информацию см. в logging documentation.
PermissionDenied
¶
-
exception
PermissionDenied
[исходный код]¶ -
Исключение
PermissionDenied
возникает, когда у пользователя нет разрешения на выполнение запрашиваемого действия.
ViewDoesNotExist
¶
-
exception
ViewDoesNotExist
[исходный код]¶ -
Исключение
ViewDoesNotExist
вызываетсяdjango.urls
, когда запрашиваемое представление не существует.
MiddlewareNotUsed
¶
-
exception
MiddlewareNotUsed
[исходный код]¶ -
Исключение
MiddlewareNotUsed
возникает, когда промежуточное ПО не используется в конфигурации сервера.
ImproperlyConfigured
¶
-
exception
ImproperlyConfigured
[исходный код]¶ -
Исключение
ImproperlyConfigured
возникает, когда Django каким-то образом неправильно настроен — например, если значение вsettings.py
неверно или не поддается разбору.
FieldError
¶
-
exception
FieldError
[исходный код]¶ -
Исключение
FieldError
возникает, когда возникает проблема с полем модели. Это может произойти по нескольким причинам:- Поле в модели конфликтует с одноименным полем из абстрактного базового класса
- Бесконечный цикл возникает при заказе
- Ключевое слово не может быть разобрано из параметров фильтра
- Поле не может быть определено по ключевому слову в параметрах запроса
- Объединение не разрешено для указанного поля
- Имя поля является недопустимым
- Запрос содержит недопустимые аргументы order_by
ValidationError
¶
-
exception
ValidationError
[исходный код]¶ -
Исключение
ValidationError
возникает, когда данные не проходят валидацию полей формы или модели. Подробнее о валидации см. в Form and Field Validation, Model Field Validation и Validator Reference.
NON_FIELD_ERRORS
¶
-
NON_FIELD_ERRORS
¶
ValidationError
, которые не принадлежат определенному полю в форме или модели, классифицируются как NON_FIELD_ERRORS
. Эта константа используется в качестве ключа в словарях, которые иначе сопоставляют поля с соответствующим списком ошибок.
BadRequest
¶
-
exception
BadRequest
[исходный код]¶ -
Исключение
BadRequest
возникает, когда запрос не может быть обработан из-за ошибки клиента. Если исключениеBadRequest
достигает уровня обработчика ASGI/WSGI, оно приводит к возникновениюHttpResponseBadRequest
.
RequestAborted
¶
-
exception
RequestAborted
[исходный код]¶ -
Исключение
RequestAborted
возникает, когда HTTP-тело, считываемое обработчиком, обрывается на середине пути и клиентское соединение закрывается, или когда клиент не отправляет данные и достигает тайм-аута, при котором сервер закрывает соединение.Он является внутренним для модулей обработчика HTTP, и вы вряд ли увидите его где-либо еще. Если вы модифицируете код обработки HTTP, вам следует вызывать это сообщение, когда вы столкнулись с прерванным запросом, чтобы убедиться, что сокет закрыт чисто.
SynchronousOnlyOperation
¶
-
exception
SynchronousOnlyOperation
[исходный код]¶ -
Исключение
SynchronousOnlyOperation
возникает, когда код, допустимый только в синхронном коде Python, вызывается из асинхронного контекста (потока с запущенным асинхронным циклом событий). Эти части Django в целом сильно зависят от потокобезопасности для функционирования и не работают корректно в корутинах, разделяющих один и тот же поток.Если вы пытаетесь вызвать код, который является только синхронным, из асинхронного потока, то создайте синхронный поток и вызывайте его в нем. Этого можно добиться с помощью
asgiref.sync.sync_to_async()
.
Исключения из URL-резольвера¶
Исключения URL Resolver определены в django.urls
.
NoReverseMatch
¶
-
exception
NoReverseMatch
[исходный код]¶ -
Исключение
NoReverseMatch
вызываетсяdjango.urls
, когда подходящий URL в вашей URLconf не может быть идентифицирован на основе предоставленных параметров.
Исключения из базы данных¶
Исключения из базы данных могут быть импортированы из django.db
.
Django обертывает стандартные исключения баз данных так, чтобы ваш код Django имел гарантированную общую реализацию этих классов.
-
exception
Error
[исходный код]¶
-
exception
InterfaceError
[исходный код]¶
-
exception
DatabaseError
[исходный код]¶
-
exception
DataError
[исходный код]¶
-
exception
OperationalError
[исходный код]¶
-
exception
IntegrityError
[исходный код]¶
-
exception
InternalError
[исходный код]¶
-
exception
ProgrammingError
[исходный код]¶
-
exception
NotSupportedError
[исходный код]¶
Обертки Django для исключений баз данных ведут себя точно так же, как и базовые исключения баз данных. Более подробную информацию смотрите в PEP 249, спецификация Python Database API Specification v2.0.
Как и в случае PEP 3134, атрибут __cause__
устанавливается с исходным (базовым) исключением базы данных, позволяя получить доступ к любой дополнительной информации.
-
exception
models.
ProtectedError
¶
Возникает для предотвращения удаления ссылающихся объектов при использовании django.db.models.PROTECT
. models.ProtectedError
является подклассом IntegrityError
.
-
exception
models.
RestrictedError
¶
Возникает для предотвращения удаления ссылающихся объектов при использовании django.db.models.RESTRICT
. models.RestrictedError
является подклассом IntegrityError
.
Исключения HTTP¶
Исключения HTTP могут быть импортированы из django.http
.
UnreadablePostError
¶
-
exception
UnreadablePostError
[исходный код]¶ -
UnreadablePostError
возникает, когда пользователь отменяет загрузку.
Исключения из сессий¶
Исключения сессий определены в django.contrib.sessions.exceptions
.
SessionInterrupted
¶
-
exception
SessionInterrupted
[исходный код]¶ -
SessionInterrupted
возникает, когда сессия уничтожается в параллельном запросе. Он является подклассомBadRequest
.
Исключения транзакций¶
Исключения транзакций определены в django.db.transaction
.
TransactionManagementError
¶
-
exception
TransactionManagementError
[исходный код]¶ -
TransactionManagementError
поднимается для любых и всех проблем, связанных с транзакциями базы данных.
Исключения в системе тестирования¶
Исключения, предоставляемые пакетом django.test
.
RedirectCycleError
¶
-
exception
client.
RedirectCycleError
¶ -
RedirectCycleError
поднимается, когда тестовый клиент обнаруживает цикл или слишком длинную цепочку перенаправлений.
Исключения в Python¶
Django также поднимает встроенные исключения Python, когда это необходимо. Более подробную информацию о Built-in Exceptions смотрите в документации Python.