본문 바로가기

그 땐 IT활동했지/그 땐 영일영 근무했지

[010/Django] django-import-export | Widget | ManyToManyWidget

728x90

문제 상황

2022.03.11 - [그 땐 IT활동했지/그 땐 영일영 근무했지] - [010/Django] django-import-export | Widget | ForeignKeyWidget

 

[010/Django] django-import-export | Widget | ForeignKeyWidget

문제 상황 https://itwithruilan.tistory.com/69 db에 핸드폰 가게들을 잘 넣었고!(↑이전 포스팅 참고) 해당 가게들 각각에 해당하는 리뷰들을 넣어야 하는 상황이 왔다. 하나의 가게에 여러 리뷰가 달릴

itwithruilan.tistory.com

어느 날 사이트의 랜딩 페이지를 새로 만들게 되었다! 설문조사 형식의 폼이 있는 랜딩 페이지 였는데 소비자들이 알림 받길 원하는 리뷰를 선택할 수 있다. 소비자들이 여러 리뷰를 고를 수 있고 하나의 리뷰가 여러 사람의 선택을 받을 수 있기 때문에 N:M 관계이다. 

이 상황은 저번에 1:N 관계를 접했을 때랑 비슷하다! (위 링크 참고!) 소비자들이 설문조사한 db들을 export할 때 제대로 된 값이 나오지 않았다. 소비자들에게 받은 정보를 잘 출력하고 싶다면 ManyToManyWidget을 사용하면 된다.

 

오늘도 공식문서 참고!

https://django-import-export.readthedocs.io/en/latest/api_widgets.html

 

Widgets — django-import-export 2.7.2.dev0 documentation

© Copyright 2012–2020, Bojan Mihelac Revision 0ad13e0c.

django-import-export.readthedocs.io

ManyToManyWidget을 활용해보자!
#models.py
from django.db import models


RESIDENCE = (
    ('Heungdeok', '흥덕구'),
    ('Cheongwon', '청원구'),
    ('Seowon', '서원구'),
    ('Sangdang', '상당구'),
)


class HopeReviewKind(models.Model):
    name = models.CharField(max_length=50, default="")
    
    
class TrustSurvey(models.Model):
    residence = models.CharField(max_length=50, choices=RESIDENCE, null=False, blank=False)
    hope_review = models.ManyToManyField(HopeReviewKind, related_name="selected_kind")
    contact = models.CharField(max_length=50, null=False, blank=False)
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)

👉🏻모델은 다음과 같다. TrustSurvey 모델에 설문조사한 내용이 저장된다. 설문조사에서 받는 내용은 거주지, 알림받고 싶은 리뷰 종류, 전화번호이고 언제 리뷰를 받았는지는 created_at을 통해 받는다.

✍🏻어떠한 리뷰를 받을지에 대한 field인 hope_reviewHopeReviewKind model을 ManyToMany로 참조하고 있다. 위에서 언급한대로 소비자도 여러 리뷰를 선택할 수 있고 하나의 리뷰도 여러 소비자의 선택을 받을 수 있기 때문이다.

🐰이제 admin.py를 어떻게 작성해야 하는지 살펴보자!

from django.contrib import admin
from import_export.widgets import ManyToManyWidget
from import_export import fields, resources
from .models import  TrustSurvey
from import_export.admin import ImportExportModelAdmin


class TrustSurveyResource(resources.ModelResource):
    residence = fields.Field(column_name = '거주지', attribute = 'residence')
    hope_review = fields.Field(column_name = '원하는 리뷰',
                               attribute = 'hope_review',
                               widget = ManyToManyWidget('HopeReviewKind', field='name')
                               )
    contact = fields.Field(column_name = '연락처', attribute = 'contact')
    created_at = fields.Field(column_name = '입력시간', attribute = 'created_at')

    class Meta:
        model = TrustSurvey
        fields = ('get_residence_display', 'hope_review', 'contact', 'created_at',)
        export_order = ('residence', 'hope_review', 'contact', 'created_at',)


class TrustSurveyAdmin(ImportExportModelAdmin):
    fields = ('residence', 'hope_review', 'contact',)
    list_display = ('id', 'residence', 'hope_review', 'contact', 'created_at',)
    resource_class = TrustSurveyResource


admin.site.register(TrustSurvey, TrustSurveyAdmin)

👉🏻모두 TrustSurveyResource를 살펴보자! 이전과는 다르게 모든 field의 column_name과 attribute를 설정해주었다. 왜냐하면 엑셀의 열이름을 model의 field명인 residence나 hope_review처럼 영어로 쓰지 않고 거주지, 원하는 리뷰 등 한글로 입력하고 싶었기 때문이다. 해당 db들은 엑셀로 export해서 대표님께 전달드려야 했기 때문에 엑셀 열이름이 한글로 되어있어야 정보를 확인하시기 편할 것 같아 한글로 설정했다!

✍🏻여기서 집중할 field는 hope_review field이다! widget을 ManyToManyWiget으로 설정했다. 형태는 다음과 같다.

class import_export.widgets.ManyToManyWidget(model, separator=None, field=None, *args, **kwargs)
  • model: ManyToMany field가 참조하는 모델이다.
  • separator: ','이 default로 설정되어 있다.
  • field: 참조하는 모델을 찾기 위해 사용하는 field명이다. defalut는 pk이다.

✍🏻나는 HopeReviewKind model을 참조하기 때문에 해당모델을 썼다. 그리고 해당 모델의 name field로 찾을 수 있게 field명은 name으로 설정했다. 이렇게 설정하면 export할 때도 pk가 아닌 name으로 나온다! 아래 csv로 export한 예시를 보자!

👉🏻위젯을 설정하지 않으면 원하는 리뷰 부분에 해독 불가능한 landing.HopeReviewKind.None 출력

👉🏻위젯을 설정하면 깔끔하게 잘 나온다!ㅎㅎ

728x90