2

I'm having and issue trying to get import-export to work for mptt models. This is my code:

models.py

from django.db import models
from mptt.models import MPTTModel, TreeForeignKey

class MyModel(MPTTModel):
    name = models.CharField(max_length=255)
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    active = models.BooleanField(default=True,null=False,blank=False)
    sort_order = models.PositiveIntegerField(default=0,null=True,blank=True)

    class MPTTMeta:
        order_insertion_by = ['name']

    class Meta:
        ordering = ['sort_order']

    def __str__(self):
        return self.name

admin.py

from django.contrib import admin
from mptt.admin import MPTTModelAdmin, DraggableMPTTAdmin
from .models import MyModel
from import_export import resources
from import_export.admin import ImportExportModelAdmin, ImportExportMixin

class MyModelResource(resources.ModelResource):

    class Meta:
        model = MyModel
        exclude = ('lft','rght','tree_id','level')

@admin.register(MyModel)
class MyModelAdmin(ImportExportMixin, DraggableMPTTAdmin):
    resource_class = MyModelResource
    list_display = ('tree_actions','indented_title','active','sort_order')
    list_editable = ('active','sort_order')
    list_display_links = ('indented_title',)

When I export it puts the name field in the parent column. When I import again it fails on the parent field:

"MyModel.parent" must be a "MyModel" instance.

Any help is greatly appreciated

tv87
  • 85
  • 5

1 Answers1

5

I was experiencing the same problem and managed to figure it out following Boddan's question: Django call 'id' expected a number but got string. Here is what I did to make it work:

models.py

from django.db import models
from mptt.models import MPTTModel, TreeForeignKey

# Create your models here.

class Category(MPTTModel):
    name        = models.CharField(max_length = 120, unique = True)
    parent      = TreeForeignKey('self', on_delete = models.CASCADE, null = True, blank = True, related_name = "children")

    class MPTTMeta: 
        order_insertion_by = ['name']

    class Meta: 
        verbose_name_plural = 'categories'

    def __str__(self):
        return self.name

admin.py

from django.contrib import admin
from mptt.admin import DraggableMPTTAdmin, TreeRelatedFieldListFilter
from import_export import resources, fields, widgets

from import_export.admin import ImportExportModelAdmin
from .models import Category

# Resource Classes
class CategoryResource(resources.ModelResource):

    parent = fields.Field(
        column_name='parent',
        attribute='parent',
        widget = widgets.ForeignKeyWidget(Category, 'name'))

    class Meta: 
        model = Category
        skip_unchanged = True
        report_skipped = True
        exclude = ('id',)
        import_id_fields = ('name',)
        fields = ('parent','name','lft','rght','tree_id','level')

# Admin Classes

@admin.register(Category)
class CategoryAdmin(ImportExportModelAdmin,DraggableMPTTAdmin):
    resource_class = CategoryResource

So in your situation, I believe your fields would be:

fields = ('parent','name','active','sort_order','lft','rght','tree_id','level')

It seems like we need to exclude the 'id' key but i'm not entirely sure why. I noticed that it would self configure the mptt structure when I imported category names the model hadn't seen before.

I'm using Django 3.0.7, django-mptt 0.11.0, and django-import-export 2.2.0. I'm new to stack-overflow so I apologize if this isn't the correct way to respond but I hope it helps!

msf
  • 96
  • 1
  • 2
  • 6