django-import-export M2M, FK

GroupWidget

どちらでも使える:

  • Users.groups
  • Permission.group_set
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from import_export import widgets, fields

class GroupWidget(widgets.ManyToManyWidget):
    def clean(self, value, row=None, *args, **kwargs):
        if not value:
            return self.model.objects.none()
        if self.field == "name":
            # 存在しない場合作成する
            ids = value.split(self.separator)
            ids = filter(None, [i.strip() for i in ids])
            return map(lambda i: self.model.objects.get_or_create(name=i)[0], ids)
        return super().clean(self, value, row=row, *args, **kwargs)

ContentTypeWidget

  • Permission.content_type など ForeingKey 定義されていると使える
  • データは {app_label}.{model} でレンダリングされるので、取り込む時に split('.') する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from import_export import fields, widgets
from django.contrib.contenttypes.models import ContentType


class ContentTypeWidget(widgets.ForeignKeyWidget):
    def clean(self, value, row=None, *args, **kwargs):
        if value is None:
            return None

        app_label, model = value.split(".")
        content_type = ContentType.objects.get_by_natural_key(app_label, model)
        return content_type

    def render(self, value, obj=None):
        return f"{value.app_label}.{value.model}"

User.groups

User の Resource を定義するにあたって、groups を name で import/export するには、以下のように記述することができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from django.contrib.auth.models import User, Group
from import_export import resources, widgets, fields



class UserResource(resources.ModelResource):
    groups = fields.Field(
        column_name='groups',
        attribute='groups',
        # widget=widgets.ManyToManyWidget(Group, field='name')
        widget=GroupWidget(Group, field='name')     # 存在しないグループは作成するWidget
    )

    class Meta:
        model = User
        import_id_fields = ("usernmae", )
        fields = ('username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'date_joined')

この例では、ManyToManyWidgetを使用して、グループ名を取得しています。これは、django-import-exportの標準の方法です。

ソース: Bing との会話 2023/6/9

Permission.group_set

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from django.contrib.auth.models import Group, Permission
from import_export import fields, resources, widgets
from django.contrib.contenttypes.models import ContentType

from .. import models


class PermissionResource(resources.ModelResource):
    group_set = fields.Field(
        column_name="group_set",
        attribute="group_set",
        widget=GroupWidget(Group, field="name"),
    )

    content_type = fields.Field(
        column_name="content_type",
        attribute="content_type",
        widget=ContentTypeWidget(ContentType, "app_label"),
    )

    class Meta:
        model = Permission
        import_id_fields = ["content_type", "codename"]
        fields = [
            "content_type",
            "codename",
            "name",
        ]