[Django Recipe] django-import-export 관리자페이지 적용.

django-import-export 관리자 페이지 적용하기.

django-import-export는 csv, xlsx 등의 파일을 읽어 데이타베이스에 저장하거나, 데이타베이스의 내용을 csv, xlsx등의 파일로 저장하는 기능을 제공한다.
지원되는 파일 포맷은 tablib 가 지원하는 형식이며, tablib는 Excel, JSON, YAML, HTML, Jira, TSV, ODS, CSV, DBF를 지원한다.

1. 설치

pip install django-import-export

2. 설정

project/settings.py 에 아래 내용 추가

INSTALLED_APPS = [
    ...
    'import_export',
    ...
]
manage.py collectstatic

3. 사용 모델은 아래와 같다.
project/app/models.py

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

    class MPTTmeta:
        order_insertion_by = ['cat_name']

    class Meta:
        unique_together = ('parent', 'slug', )
        verbose_name_plural = 'categories'

    def get_slug_list(self):
        try:
            ancestors = self.get_ancestors(include_self=True)
        except:
            ancestors = list()
        else:
            ancestors = [i.slug for i in ancestors]
        slugs = list()
        for i in range(len(ancestors)):
            slugs.append('/'.join(ancestors[:i+1]))
        return slugs

    def __str__(self):
        return self.name


class DevInfo(models.Model):
    dev_ipa = models.GenericIPAddressField(default='0.0.0.0')
    dev_ip = models.BigIntegerField(blank=True, null=True)
    dev_cat = TreeForeignKey('Category', null=True, blank=True, on_delete=models.SET_NULL)
    admin_id = models.CharField(max_length=24)
    admin_passwd = encrypt(models.CharField(max_length=50))
    conn_protocol = models.CharField(max_length=10)
    conn_port = models.CharField(max_length=5)
    dev_vendor = models.CharField(max_length=32)
    dev_model = models.CharField(max_length=32, null=True, blank=True)
    dev_hostname = models.CharField(max_length=64, null=True, blank=True)
    dev_isl3 = models.BooleanField(default=False)
    is_gather = models.BooleanField(default=False)
    dev_link = models.TextField(null=True, blank=True)

    # auto populate dev_ip field from dev_ipa field.
    def save(self, *args, **kwargs):
        self.dev_ip = int(IPv4Address(self.dev_ipa))
        super(DevInfo, self).save(*args, **kwargs)

4. 관리자페이지에서 사용하기

관리자 페이지에 DevInfo 모델이 표시되도록 클래스를 작성한다.
project/app/admin.py

class DevInfoAdmin(admin.ModelAdmin):
    resource_class = DevInfo
    list_display = ['dev_ipa', 'dev_cat', 'admin_id', 'dev_vendor', 'dev_hostname', 'dev_isl3', 'is_gather']
    search_fields = ['ipa', 'dev_hostname']


admin.site.register(Category, DraggableMPTTAdmin)
admin.site.register(DevInfo, DevInfoAdmin)

import-export 적용전 관리자 페이지는 아처럼 보인다.

관리자 페이지에 import-export 적용하기위해 아래 모듈을 import 한다.

project/app/admin.py 에 해당 모듈을 등록

from import_export import resources, fields
from import_export.admin import ImportExportActionModelAdmin
from import_export.widgets import ForeignKeyWidget

이제, resources.ModelResource 를 상속받는 클래스 DevInfoRecource 를 작성 한다.

class DevInfoResource(resources.ModelResource):
    dev_cat = fields.Field(
        column_name='dev_cat', attribute='dev_cat',
        widget=ForeignKeyWidget(Category, 'name')
    )

    class Meta:
        model = DevInfo
        exclude = ('id', 'dev_ip',)

dev_cat=field.Field 구문은 category id 대신 category name 으로 import 하기위한 구문이다.
(category는 이전글 django-adminlte3 관련 글을 참고)

Meta 클래스의 exclude 문은 import/export 할때 제외할 필드다. id 는 primary key를 지정하지 않았을때 자동으로 생기는 필드이며, dev_ip 필드는 자동으로 ip 주소로부터 자동으로 채워지는 필드라 import/export에 필요하지 않다.

관리자 페이지에서 보여줄 클래스를 수정한다.

class DevInfoAdmin(ImportExportActionModelAdmin):
    resource_class = DevInfoResource

아래 그림처럼 import 버튼이 보인다.

xlsx 포맷으로 import 데이타를 작성한다.

이제, import를 선택하면 아래처럼 import 할 데이타의 field를 보여준다.

import를 성공하면,

이제 데이타가 아래처럼 object로 표시된다.

데이타가 위처럼 object로 표시되면 확인하기 불편하다. 이제, 원하는 필드를 보여주기위해서 클래스에 list_display를 추가하고, 관리자페이지의 검색 기능에 검색할 필드를 search_field로 지정한다.

class DevInfoAdmin(ImportExportActionModelAdmin):
    resource_class = DevInfoResource
    list_display = ['dev_ipa', 'dev_cat', 'admin_id', 'dev_vendor', 'dev_hostname', 'dev_isl3', 'is_gather']
    search_fields = ['dev_ipa', 'dev_hostname']

이제, 데이타가 위에서 object 대신 지정한 필드를 보여준다.

7 comments

Skip to comment form

    • Moo on 2022년 6월 30일 at 5:29 오후
    • Reply

    글 잘 보았습니다. 한 가지 궁금한 것이 있는데 질문을 해도 될까요?

    1. 네.
      ;^^

    • Moo on 2022년 6월 30일 at 5:29 오후
    • Reply

    글 잘 보았습니다. 이것 관련해서 질문 한가지만 드려도 될까요?

    • Moo on 2022년 6월 30일 at 5:38 오후
    • Reply

    감사합니다. ㅠㅠ
    django import_export를 무난하게 잘 사용하다가
    외래키로 연결되어 있는 것을 가져오려니 잘 되지 않아서요.. 혹시 해결방법을 알까 싶어 연락드렸습니다. ㅠㅠ
    내보내는것은 잘 되는데 가져오면 에러가 나오네요..

    import export foreign key error 라고 검색해서 스택오버플로우에 있는 글을 다 보고
    import export 공식 페이지에서 ForeignKeyWidget 을 보고 따라했는데도 아직 많이 미숙한가봅니다.
    경험이 있으시고 해결한 부분이 있다면 도움을 얻고 싶어 글을 남깁니다 ㅠㅠ

    1. 남겨주신 내용만 가지고는 정확히 어떤 문제일지 판단이 안되네요.
      다만, 사용하던 모델에 외래키를 추가했다면,
      1. 변경된 model을 migrate 하지 않았을 가능성.
      2. migrate 했다면 admin.py에서 import-export 하기위한 관련 부분쪽 문제일 가능성.
      우선 생각나는게 두가지인데요.

      혹시 관련 코드를 보여주실 수 없는 상황인지요?

        • Moo on 2022년 6월 30일 at 7:22 오후
        • Reply

        다행히 잘 해결되었습니다. ^ㅁ^
        2일동안 검색하다 해결이 안되서 목욕물에 물받고 2시간 놀다온 후 여기에 질문을 올린거였는데
        올리고나서 스택오버플로우 옛날에 봤던 것들부터 하나씩 다시 보면서 하다보니 해결되었네요.
        문제점은 ForeignKeyWidget을 제대로 사용한게 맞았지만 실제 서버의 id값과
        테스트서버의 id값이 서로 달라 에러를 배출했던 것이었습니다..
        이곳에 글을 올리고 나서 바로 술술 풀려버리듯이 잘 해결되어서 감사의 인사를 적습니다.
        정말 감사드립니다~!

        1. 막힐땐 쉬는것도 좋지요!
          별 도움이 안된것 같지만, 그래도 잘 해결하셨다니 기쁘네요!

답글 남기기

Your email address will not be published.