Search code examples
pythondjangodjango-import-export

Django-import-export - How to pass user information to ForeignKeyWidget?


I need to somehow pass the user information to ForeignKeyWidget class from resource class, where I create ForeignKey object:

class CompanyWidget(ForeignKeyWidget):

    def clean(self, value, row=None, *args, **kwargs):
        print(self.user, file=sys.stderr)
        if not value:
            return None
        else:
            obj, _ = Company.objects.get_or_create(
                name=value,
                created_by='I NEED USER INFORMATION HERE SOMEHOW',

            )
        return obj

What is the best way to do this?


I've tried to solve this on my own and got pretty close, but could not fit the last piece of the puzzle. You override __init__ class in resource and get user information there. Then, I could not figure out how to pass this self.user information into the class variable company.

Here is the code:

class ContactResource(resources.ModelResource):
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ContactResource, self).__init__(*args, **kwargs)

    company = fields.Field(
        column_name='company',
        attribute='company',
        widget=CompanyWidget(model=Company, field='name', user='I NEED TO PASS USER HERE FROM __INIT__'))

    def after_import_instance(self, instance, new, **kwargs):
        instance.created_by = kwargs['user']

If I somehow manage to pass user information in **kwargs of company variable, then I can use it downstream by overriding ForeignKeyWidget's __init__ class:

class CompanyWidget(ForeignKeyWidget):
    def __init__(self, model, field='pk', *args, **kwargs):
        self.model = model
        self.field = field
        self.user = kwargs.pop('user', None)
        super(CompanyWidget, self).__init__(model, *args, **kwargs)

    def clean(self, value, row=None, *args, **kwargs):
        print(self.user, file=sys.stderr)
        if not value:
            return None
        else:
            obj, _ = Company.objects.get_or_create(
                name=value,
                created_by=self.user,

            )
        return obj

Any help would be appreciated, it took me forever to get here and I feel I am really close. Thank you in advance.


Solution

  • It turns out it is easier to implement this without using ForeignKeyWidget at all. If you have multiple foreign keys that are not unique but have the same name (in my case, same company name created by different users), this is how you could solve the problem:

    class ContactResource(resources.ModelResource):

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ContactResource, self).__init__(*args, **kwargs)
    
    company = fields.Field(column_name='company')
    
    class Meta:
        model = Contact
        skip_unchanged = True
        report_skipped = True
        exclude =('is_active', 'created_by')
        export_order = ('id','first_name','last_name','email','phone','address','description','company','created_on','website','job_title','birthday')
    
    def after_import_instance(self, instance, new, **kwargs):
        instance.created_by = self.user # kwargs['user']
    
    def import_field(self, field, obj, data):
        field_name = self.get_field_name(field)
        method = getattr(self, 'clean_%s' % field_name, None)
        if method is not None:
            obj = method(field, obj, data)
        super(ContactResource, self).import_field(field, obj, data)
    
    def clean_company(self, field, obj, data):
        name = data[field.column_name]
        company, created = Company.objects.get_or_create(name=name, created_by=self.user)
        obj.company = company
        return obj