0

I'm experiencing a persistent issue with importing CSV data into my Django project using the django-import-export library in the admin panel. When trying to import records for a Copy model which has ForeignKey relations, I keep encountering a NOT NULL constraint failed error for the book_id field. AGAIN THIS ONLY OCCURS IN THE ADMIN PANEL, I have tested in shell and it works. I am sure there is no issue with the CSV and likely not even the resources/models files. It seems something is going wrong with the admin logic before the actual import.

Error looks like this but for every single row. It occurs when hitting "submit". I never even get to "Confirm Import" button

Line number: 1 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 2 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 3 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 4 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 5 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 6 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 7 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 8 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 9 - NOT NULL constraint failed: catalog_copy.book_id
Line number: 10 - NOT NULL constraint failed: catalog_copy.book_id

Here are the relevant parts of my code:

models.py

from django.db import models
from django.core.exceptions import ValidationError

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    isbn = models.CharField(max_length=13)

class Format(models.Model):
    name = models.CharField(max_length=100)

class Copy(models.Model):
    book = models.ForeignKey(Book, related_name='copies', on_delete=models.CASCADE)
    format = models.ForeignKey(Format, related_name='copies', on_delete=models.CASCADE)
    location = models.CharField(max_length=100)
    is_available = models.BooleanField(default=True)

resources.py

from import_export import resources
from .models import Copy

class CopyResource(resources.ModelResource):
    class Meta:
        model = Copy
        fields = ('id', 'book', 'format', 'location', 'is_available')
        import_id_fields = ['id']

    def before_import_row(self, row, **kwargs):
        book_title = row.get('Book Title')
        isbn = row.get('ISBN')
        author = row.get('Author')
        format_name = row.get('Format')
        
        book, created = Book.objects.get_or_create(
            title=book_title,
            defaults={'isbn': isbn, 'author': author}
        )
        format, created = Format.objects.get_or_create(
            name=format_name
        )

        row['book'] = book.pk
        row['format'] = format.pk

admin.py

from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from .models import Copy
from .resources import CopyResource

class CopyAdmin(ImportExportModelAdmin):
    resource_class = CopyResource

admin.site.register(Copy, CopyAdmin)

I've manually verified the CSV and even tested uploading in the django shell which worked properly. But admin panel still does not work!!!

        import tablib
   ...: from catalog.resources import CopyResource
   ...: 
   ...: with open('library_copies.csv', 'r', encoding='utf-8') as f:
   ...:     data = tablib.Dataset().load(f.read(), format='csv')
   ...: 
   ...: resource = CopyResource()
   ...: result = resource.import_data(data, dry_run=False)
   ...: 
   ...: if result.has_errors():
   ...:     print("Errors occurred during the import:")
   ...:     for error in result.base_errors:
   ...:         print(f"Base error: {error.error}")
   ...: else:
   ...:     print("The import would proceed without errors.")

The above succeeds but import through admin panel always has NOT NULL error

Edit: Adding logs for manual shell run vs admin panel. It leads me to believe the CopyResource logic is not being used at all in the admin panel, and I cannot figure out why. It says Resource: CopyResource in the admin panel, but it does not follow the proper logic like in shell.

shell:

0.000) BEGIN; args=None; alias=default
(0.000) SAVEPOINT "s8585724224_x6"; args=None; alias=default
(0.000) RELEASE SAVEPOINT "s8585724224_x6"; args=None; alias=default
(0.000) SAVEPOINT "s8585724224_x7"; args=None; alias=default
Before importing row... OrderedDict({'id': '1', 'Book Title': 'Thank You for My Service ', 'ISBN': '9781524796501', 'Author': 'Mat Best', 'Format': 'Large Print', 'Location': 'Juliefurt', 'Is Available': 'True'})
Row data: OrderedDict({'id': '1', 'Book Title': 'Thank You for My Service ', 'ISBN': '9781524796501', 'Author': 'Mat Best', 'Format': 'Large Print', 'Location': 'Juliefurt', 'Is Available': 'True'})
(0.000) SELECT "catalog_book"."id", "catalog_book"."title", "catalog_book"."author", "catalog_book"."isbn" FROM "catalog_book" WHERE "catalog_book"."title" = 'Thank You for My Service ' LIMIT 21; args=('Thank You for My Service ',); alias=default
(0.000) SAVEPOINT "s8585724224_x8"; args=None; alias=default
(0.000) INSERT INTO "catalog_book" ("title", "author", "isbn") VALUES ('Thank You for My Service ', 'Mat Best', '9781524796501') RETURNING "catalog_book"."id"; args=('Thank You for My Service ', 'Mat Best', '9781524796501'); alias=default
(0.000) ROLLBACK TO SAVEPOINT "s8585724224_x8"; args=None; alias=default
(0.000) RELEASE SAVEPOINT "s8585724224_x8"; args=None; alias=default
(0.000) RELEASE SAVEPOINT "s8585724224_x7"; args=None; alias=default
(0.000) SAVEPOINT "s8585724224_x9"; args=None; alias=default
Before importing row... OrderedDict({'id': '2', 'Book Title': 'Thank You for My Service ', 'ISBN': '9781524796501', 'Author': 'Mat Best', 'Format': 'Large Print', 'Location': 'Hernandezport', 'Is Available': 'True'})

admin panel:

(0.000) BEGIN; args=None; alias=default
(0.000) SAVEPOINT "s6196490240_x1"; args=None; alias=default
(0.000) RELEASE SAVEPOINT "s6196490240_x1"; args=None; alias=default
(0.000) SAVEPOINT "s6196490240_x2"; args=None; alias=default
(0.000) SELECT "catalog_copy"."id", "catalog_copy"."book_id", "catalog_copy"."format_id", "catalog_copy"."location", "catalog_copy"."is_available" FROM "catalog_copy" WHERE "catalog_copy"."id" IS NULL LIMIT 21; args=(); alias=default
(0.000) INSERT INTO "catalog_copy" ("book_id", "format_id", "location", "is_available") VALUES (NULL, NULL, '', 1) RETURNING "catalog_copy"."id"; args=(None, None, '', True); alias=default
(0.000) ROLLBACK TO SAVEPOINT "s6196490240_x2"; args=None; alias=default
(0.000) RELEASE SAVEPOINT "s6196490240_x2"; args=None; alias=default
(0.000) SAVEPOINT "s6196490240_x3"; args=None; alias=default
(0.000) SELECT "catalog_copy"."id", "catalog_copy"."book_id", "catalog_copy"."format_id", "catalog_copy"."location", "catalog_copy"."is_available" FROM "catalog_copy" WHERE "catalog_copy"."id" IS NULL LIMIT 21; args=(); alias=default

4
  • which version of django-import-export are you using? Commented May 10, 2024 at 8:21
  • @MatthewHegarty Thank you for helping!!! Name: django-import-export Version: 4.0.0 Commented May 10, 2024 at 15:32
  • I suggest trying in 3.3.8 just to see if it is a regression in v4 Commented May 10, 2024 at 16:51
  • @MatthewHegarty , It worked!!!! You are a gentleman and a scholar Commented May 10, 2024 at 21:13

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.