简体   繁体   中英

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.

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.')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM