python/Django

[Django] ModelAdmin 상에서 list_display 내에서 ManyToMany 필드의 상위 세부 내역조회 하기 - (다대다관계 2)

http://portfolio.wonpaper.net 2022. 5. 24. 23:29

다:다 관계로 이루어진 다음과 같은 모델 자료가 있다고 할때

ManyToMany 필드를 통하여 상위 세부 내역을 조회하고 이를 관리자페이지상의 ModelAdmin 형태로 나타내고자 한다.

 

다음 캡처이미지와 소스는 필자가 나름 고찰하여 만들어 보았다.

 

Member 와 Lecture 가 다:다 관계의 모델이고, Lecture Member 가  1:다:1의 중간 테이블모델이다.

 

SQL 구문과 같이 다대다 관계는 원래 1:다:1 형태의 테이블로 구분하여 처리해 준다.

장고상의 ORM 역시 이부분과 동일하게 생각하면 된다.

그리고, Member 모델의 데이터는 아래와 같다.

 

[ member/models.py ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.db import models
 
 
class Member(models.Model):
    mem_id = models.CharField(db_column='mem_id',max_length=50, unique=True)
    passwd = models.CharField(db_column='passwd', max_length=255)
    name = models.CharField(db_column='name', max_length=50)
    email = models.CharField(db_column='email', max_length=50, blank=True)
    usage_flag = models.CharField(db_column='usage_flag', max_length=10, default='y')
    log_cnt = models.IntegerField(db_column='log_cnt', default=0)
    reg_date = models.DateTimeField(db_column='reg_date', auto_now_add=True)
    update_date = models.DateTimeField(db_column='update_date', auto_now=True)
 
    class Meta:
#        managed = False
        db_table = 'member'
 
    def __str__(self):
        return '이름 : ' + self.name + ", 이메일 : " + self.email
cs

 

[ lecture/models.py ]

 

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
29
30
31
32
33
34
35
36
37
from django.db import models
 
from member.models import Member
 
 
class Lecture(models.Model):
    member = models.ManyToManyField(Member, through='LectureMember', blank=True)
 
    lecture_name = models.CharField(db_column='lecture_name', max_length=255)
    content = models.TextField(db_column='content', blank=True)
    read_num = models.IntegerField(db_column='read_num', default=0)
    reg_date = models.DateTimeField(db_column='reg_date', auto_now_add=True)
    update_date = models.DateTimeField(db_column='update_date', auto_now=True)
 
    image1 = models.ImageField(db_column='image1', upload_to='lecture/image1/%Y/%m/%d/', max_length=255, blank=True)
    upfile1 = models.FileField(db_column='upfile1', upload_to='lecture/upfile1/%Y/%m/%d/', max_length=255, blank=True)
 
    class Meta:
        db_table = 'lecture'
 
    def __str__(self):
        return f"강의명 : {self.lecture_name}"
 
 
# 1:다:1 테이블
class LectureMember(models.Model):
    member = models.ForeignKey(Member, db_column='member_id', on_delete=models.CASCADE, related_name='memberOf')
    lecture = models.ForeignKey(Lecture, db_column='lecture_id', on_delete=models.CASCADE, related_name='lectureOf')
 
    jumsu = models.IntegerField(db_column='jumsu', default=0)
    reg_date = models.DateTimeField(db_column='reg_date', auto_now_add=True)
 
    class Meta:
        db_table = 'lecture_member'
 
    def __str__(self):
        return f"강의 : {self.lecture.lecture_name}, 회원 : {self.member.name}"
cs

위의 소스중에 7라인 ManyToMany 가 이부분이다.

through='LectureMember' 을  통하여 1:다:1 에서 다에 해당하는 LectureMember 모델을 따로 두고 있는데, 

실제상에서는 이 옵션을 만들지 않아도 장고는 내부적으로 처리되는데, 

필자는 전체 프로그램 흐름 이해를 위해서 만들어 두었다.

 

[ /member/admin.py ]

 

1
2
3
4
5
6
7
8
from django.contrib import admin
from .models import Member
 
class MemberAdmin(admin.ModelAdmin):
    list_display = ('mem_id''name''email')
 
 
admin.site.register(Member, MemberAdmin)
cs

 

 

[ /lecture/admin.py ]

 

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
29
30
31
32
33
34
35
36
37
from django.contrib import admin
from .models import Lecture, LectureMember
 
 
class LectureAdmin(admin.ModelAdmin):
    list_display = ('lecture_name''get_members_mem_id',  'get_members_name''update_date')
 
    def get_members_mem_id(self, obj):
        return ', '.join([m.mem_id for m in obj.member.all()])
    get_members_mem_id.short_description = '아이디'
 
    def get_members_name(self, obj):
        return ', '.join([m.name for m in obj.member.all()])
    get_members_name.short_description = '이름'
 
 
admin.site.register(Lecture, LectureAdmin)
 
 
class LectureMemberAdmin(admin.ModelAdmin):
    list_display = ('get_lecture_name''get_mem_id',  'get_member_name''jumsu''reg_date' )
 
    def get_lecture_name(self, obj):
        return obj.lecture.lecture_name
    get_lecture_name.short_description = '강의명'
 
    def get_mem_id(self, obj):
        return obj.member.mem_id
    get_mem_id.short_description = '아이디'
 
    def get_member_name(self, obj):
        return obj.member.name
    get_member_name.short_description = '이름'
 
 
admin.site.register(LectureMember, LectureMemberAdmin)
 
cs

 

마지막 /lecture/admin.py 소스는 관리자페이지 소스이다.

8~ 10라인과 같이 get_members_mem_id, get_members_name 함수를 각각 만들고,

ManyToMany 필드와 연결된 member 모델을 [m.mem_id for m in obj.member.all()] 이런식으로 리스트 형태로 모아서 조회할 수 있다.

 

참고 : https://stackoverflow.com/questions/18108521/many-to-many-in-list-display-django