Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django-import-export, importing ManyToMany from XLSX

For my current project I need to import data from excelsheets format .xlsx to the django-admin. I'm struggling with the many2many relations that I have in my models. The importing feature just doesn't recognize the many2many fields and imports only the remaining fields (normal and foreignkey). Same goes for exporting, all fields except the many2many get exported into a excelsheet, although I dont need this feature, just tested it.

For better understanding the code snippets from my models.py, admin.py, resources.py and widgets.py.

I tried the default many2many widget -> in the TeacherResource in resources.py and I also tired overriding the default m2m widget -> StudyfieldWidget in widgets.py

models.py

class Translation(models.Model):
    de = models.TextField(unique=True)
    en = models.TextField(unique=True)

    def __str__(self):
        return self.de 

class Studyfield(models.Model):
    degree = models.CharField(max_length=50)
    title = models.ForeignKey("Translation", on_delete=models.CASCADE, related_name="+")

    def __str__(self):
        return self.title


class Course(models.Model):
    number = models.CharField(max_length=50)
    title = models.ForeignKey("Translation", on_delete=models.CASCADE, related_name="+")

    studyfields = models.ManyToManyField("Studyfield", related_name="course", blank=True)

    def __str__(self):
        return self.title
        

class Teacher(models.Model):
    name = models.CharField(max_length=50, blank=True)

    studyfields = models.ManyToManyField("Studyfield", related_name="teacher", blank=True)
    courses = models.ManyToManyField("Course", related_name="teacher", blank=True)

    def __str__(self):
        return self.name



admin.py

@admin.register(Translation)
class TranslationAdmin(ImportExportModelAdmin):
    resource_class = TranslationResource
    ordering = ('id',)
    formats = [base_formats.XLSX]

@admin.register(Studyfield)
class StudyfieldAdmin(ImportExportModelAdmin):
    resource_class = StudyfieldResource
    ordering = ('id',)
    formats = [base_formats.XLSX]

@admin.register(Course)
class CourseAdmin(ImportExportModelAdmin):
    resource_class = CourseResource
    ordering = ('id',)
    formats = [base_formats.XLSX]
    
@admin.register(Teacher)
class TeacherAdmin(ImportExportModelAdmin):
    resource_class = TeacherResource
    ordering = ('id',)
    formats = [base_formats.XLSX]


resources.py

class TranslationResource(resources.ModelResource):
    class Meta:
        model = Translation
        fields = ('id', 'de', 'en')


class StudyfieldResource(resources.ModelResource):
    title = fields.Field(
        column_name = 'title',
        attribute = 'title',
        widget = TranslationWidget(Translation, 'de'),
    )

    class Meta:
        model = Studyfield
        fields = ('id', 'degree', 'title')


class CourseResource(resources.ModelResource):
    title = fields.Field(
        column_name = 'title',
        attribute = 'title',
        widget = TranslationWidget(Translation, 'de')
    )

    studyfields = fields.Field(
        widget = StudyfieldWidget(Studyfield)
    )

    class Meta:
        model = Course
        fields = ('id', 'number', 'title', 'studyfields')


class TeacherResource(resources.ModelResource):
    studyfields = fields.Field(
        widget = ManyToManyWidget(Studyfield)
    )

    courses = fields.Field(
        widget = ManyToManyWidget(Course)
    )

    class Meta:
        model = Teacher
        fields = ('id', 'name', 'studyfields', 'courses')
    

    
widgets.py

class TranslationWidget(widgets.ForeignKeyWidget):
    def clean(self, value, row=None, *args, **kwargs):
        return self.model.objects.get_or_create(de=value)[0] if value else None

       

class StudyfieldWidget(widgets.ManyToManyWidget):
    def clean(self, value, row=None, *args, **kwargs):
        if not value:
            return self.model.objects.none()
        if isinstance(value, (float, int)):
            ids = [int(value)]
        else:
            ids = value.split(self.separator)
            ids = filter(None, [i.strip() for i in ids])
        return self.model.objects.filter(**{
            '%s__in' % self.field: ids
        })
like image 504
Lena M Avatar asked Oct 15 '25 04:10

Lena M


1 Answers

So i finally got around to fix this problem and the solution was actually pretty simple:

studyfields = fields.Field(
    column_name = 'provider',
    attribute='provider',
    widget=widgets.ManyToManyWidget(Studyfield, field='title', separator=',')
)

As soon as I added the column_name it worked.

like image 184
Lena M Avatar answered Oct 17 '25 02:10

Lena M



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!