redoc
redoc

Reputation: 71

foreign key in django-import-export

First of all pardon me for my poor English. I'm using django-import-export to upload excel file into my student model that has foreign key relationship with university model

student.. models.py:

class Student(models.Model):
    institution = models.ForeignKey(University, on_delete=models.CASCADE)
    id = models.CharField(max_length=200, primary_key=True)
    first_name = models.CharField(max_length=200)
    middle_name = models.CharField(max_length=200)
    last_name =  models.CharField(max_length=200)
    age = models.IntegerField()
    faculty = models.CharField( max_length=200, null=True, blank=True)
    program = models.CharField( max_length=200, null=True, blank=True)


    def __str__(self):
        return self.first_name

university.. models.py:

class University(models.Model):
    name = models.CharField(max_length=300)
    email = models.EmailField(max_length=255, unique=True)
    phone_no1 = PhoneNumberField()
    phone_no2 = PhoneNumberField(blank=True)
    fax_no = PhoneNumberField()
    website = models.URLField(max_length=200)
    pob = models.IntegerField()
    city = models.CharField(max_length=200, blank=True)
    logo = models.ImageField(upload_to="logos/", blank=True, null=True)

    def __str__(self):
        return self.name

After reading django-import-export documentation about ForeignKeyWidget I edited my resources.py file as following and it works fine when I upload excel file that contain institution id and other student information

resources.py

class StudentResource(resources.ModelResource):
    institution = fields.Field(
        column_name='institution',
        attribute ='institution',
        widget = ForeignKeyWidget(University, 'id')
        
    )
    class Meta:
        model=Student

But I don't want to include institution id into my excel file while I am uploading, because I can find the institution id from Registrar Staff logged in since the RegistrarStaff model has foreign key relationship with university model

class RegistrarStaff(models.Model):
    user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key = True)
    university = models.ForeignKey(University, on_delete=models.CASCADE, null=True)
    phone_number = models.CharField(max_length=20)
    
    
    def __str__(self):
       return str(self.user)

This is the way I able to find institution id based on whose university Registrar Staff is logged in and passed the value into resource like on number 4 in views.py

views.py:

def upload(request):
    if request.method == 'POST':
        loged=request.user.id
        univ = RegistrarStaff.objects.get(pk=loged).university_id
        student_resource = StudentResource(institution=univ)
        dataset = Dataset()
        new_student = request.FILES['myfile']
        if not new_student.name.endswith('xlsx'):
            messages.info(request,'Wrong format')
            return render(request, 'upload.html')
        
        imported_data = dataset.load(new_student.read(), format='xlsx')
        for data in imported_data:
            value = Student(
                data[0],
                data[1],
                data[2],
                data[3],
                data[4],
                data[5],
            )
            value.save()
            
     
    return render(request, 'upload.html')

And I intialized it in resources.py as follow

resources.py:

class StudentResource(resources.ModelResource):
    
    def __init__(self, *args, **kwargs):
        self._institution=kwargs.pop('institution', None)
        super().__init__(*args, **kwargs)

        print(self._institution)
   
    class Meta:
        model=Student

So, is there anyway I can set the value of institution id = self._institution so as to able to upload excel file that doesn't contain institution id????

Upvotes: 2

Views: 2211

Answers (1)

Matthew Hegarty
Matthew Hegarty

Reputation: 4231

You are on the right lines. The way to do this is to pass the institution instance (or id) into the constructor, which is what you have already. All you need to do is to set the institution instance onto the Student model instance before it is saved:

class StudentResource(resources.ModelResource):
    
    def __init__(self, *args, **kwargs):
        self._institution=kwargs.pop('institution', None)
        super().__init__(*args, **kwargs)

        print(self._institution)

    def before_save_instance(self, instance, using_transactions, dry_run):
        setattr(instance, "institution", self._institution)
   
    class Meta:
        model=Student

However, you are bypassing the django-import-export framework by calling Student.save() directly. Don't do this. Use the framework to handle instance creation for you (docs):

result = student_resource.import_data(imported_data, dry_run=True)

Upvotes: 2

Related Questions