R4chi7 R4chi7 - 1 month ago 11
Python Question

Django Integrity Error in Bulk Import via CSV in Admin

I am trying to implement a CSV Import in Django Admin and save bulk data corresponding to the CSV file's rows. I have a model

Employee
with a
OneToOneField
to Django's
Auth
model. I have written a custom Form that accepts a csv file. However, when I call the super().save() method, I get an Integrity Error.

My Model class is:

class Employee(models.Model):
user = models.OneToOneField(User, primary_key=True)
company = models.ForeignKey(Companies)
department = models.ForeignKey(Departments)
mobile = models.CharField(max_length=16, default="0", blank=True)
gender = models.CharField(max_length=1, default="m", choices=GENDERS)
image = models.ImageField(upload_to=getImageUploadPath, null=True, blank=True)
designation = models.CharField(max_length=64)
is_hod = models.BooleanField(default=False)
is_director = models.BooleanField(default=False)


This is my Admin class:

class EmployeeAdmin(admin.ModelAdmin):
list_display = ('user', 'company', 'department', 'designation', 'is_hod', 'is_director')
search_fields = ['user__email', 'user__first_name', 'user__last_name']
form = EmployeeForm


This is my Form class:

class EmployeeForm(forms.ModelForm):
company = forms.ModelChoiceField(queryset=Companies.objects.all())
file_to_import = forms.FileField()

class Meta:
model = Employee
fields = ("company", "file_to_import")

def save(self, commit=True, *args, **kwargs):
try:
company = self.cleaned_data['company']
records = csv.reader(self.cleaned_data['file_to_import'])
for line in records:
# Get CSV Data.

# Create new employee.
employee = CreateEmployee(email, firstName, lastName, gender, '', company.id, dept[0].id, designation,
isSuperuser, isHod, isDirector)
super(EmployeeForm, self).save(*args, **kwargs)

except Exception as e:
traceback.print_exc()
raise forms.ValidationError('Something went wrong.')


The
CreateEmployee
method is defined as:

@transaction.atomic
def CreateEmployee(email='', firstName='', lastName='', gender='', mobile='',
companyId='', departmentId='', designation='', isSuperuser=False, isHod=False, isDirector=False):
try:
user = User(
username=email,
email=email,
first_name=firstName,
last_name=lastName,
is_superuser=isSuperuser,
is_active=True)
password = getPassword(firstName, lastName)
user.set_password(password)
user.save()

company = Companies(id=companyId)
dept = Departments(id=departmentId)

employee = Employee(
user=user,
mobile=mobile,
gender=gender,
designation=designation,
company=company,
department=dept,
is_hod=isHod,
is_director=isDirector)
employee.save()
return employee
except DatabaseError as e:
raise e
return None


I am getting an exception in the form's except block with the error:
IntegrityError: (1048, "Column 'user_id' cannot be null")


In the traceback, I can see that the exception is being raised in the
super(EmployeeForm, self).save(*args, **kwargs)
line. I am assuming the super method is trying to save an instance.

The complete traceback is:

Traceback (most recent call last):
File "/home/rachit/Projects/project/users/forms.py", line 81, in save
super(EmployeeForm, self).save(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py", line 455, in save
construct=False)
-- lot of text --
IntegrityError: (1048, "Column 'user_id' cannot be null")


I am guessing the ModelForm's save method is trying to save an instance, but I don't want that to happen as I have created multiple users.

What am I doing wrong here? Is there an alternative way to achieve what I want?

TIA.

2ps 2ps
Answer

Since you’re doing your own save, you don’t need to call save on the Super form. Typically when you have foreign key fields that you need to fill in like this, you use commit=False to get an instance of the unsaved model., but you can do either of these:

def save(self, commit=True, *args, **kwargs):
    try:
        company = self.cleaned_data['company']
        records = csv.reader(self.cleaned_data['file_to_import'])
        for line in records:
            # Get CSV Data.

            # Create new employee.
            employee = CreateEmployee(email, firstName, lastName, gender, '', company.id, dept[0].id, designation, 
                       isSuperuser, isHod, isDirector)
        # super(EmployeeForm, self).save(*args, **kwargs)
        # - or -
        super(EmployeeForm, self).save(commit=False)
        # updated based on additional comment
        return employee

    except Exception as e:
        traceback.print_exc()
        raise forms.ValidationError('Something went wrong.')
Comments