[Django] ModelAdmin 상에서 list_display 내에서 ManyToMany 필드의 상위 세부 내역조회 하기 - (다대다관계 2)
다:다 관계로 이루어진 다음과 같은 모델 자료가 있다고 할때
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