Как правильно использовать get_or_create в django?

Как может быть, что get_or_create приводит к:

pymysql.err.IntegrityError: (1062, "Дублирующая запись '...blabla' для ключа 'descriptor'")

пожалуйста, посмотрите, как я вызываю get_or_create:

for key in keys:
    files_obj, created = Files.objects.get_or_create(file_path=key,
                                                     file_name=Path(key).name,
                                                     libera_backend=resource_object)
    if created:
        files_obj_uuids.append(files_obj.pk)
        resource_objects.append(resource_object.pk)

спасибо заранее

Проблема здесь, скорее всего, связана с тем, как вы используете первичные ключи (или уникальные ограничения). В вашей модели поле file_path, вероятно, уникально, что означает, что никакие две строки не могут иметь одинаковое значение.

Когда вы используете get_or_create, переданные вами поля сначала используются в предложении "where" вместе, эффективно делая то же самое, что и:

files = Files.objects.filter(file_path=key,
                             file_name=Path(key).name,
                             libera_backend=resource_object)
if not files.exists():
  files = Files(file_path=key
                file_name=Path(key).name,
                libera_backend=resource_object)
...

Теперь на первом filter вы ничего не получаете, потому что нет записи, соответствующей всем трем полям, поэтому вы пытаетесь создать новый объект Files с помощью file_path=key, что приводит к ошибке, потому что нарушается ограничение для этого поля.

Решением может быть изменение модели для удаления ограничения file_path, или, возможно, сделать ограничение unique комбинацией из file_path, file_name и libera_backend. В качестве альтернативы можно использовать параметр defaults в get_or_create:

files_obj, created = Files.objects.get_or_create(file_path=key,
                                                 defaults={'file_name': Path(key).name,                                      
                                                           'libera_backend': resource_object})
Вернуться на верх