ForeignKey
로 다른 테이블의 모델(레코드)을 연결하면 그 모델의 필드도 사용할 수 있다. 예를 들어 User
모델이 name, age 필드를 가지고 이것이 Post
모델에 연결된다고 가정하자.
class Post():
title = models.TextFiled()
user = models.ForeignKey("users.User", on_delete = models.CASCADE)
def __str__(self):
return self.user.name
이렇게 Post
모델에서 연결된 User
모델의 name 필드를 사용할 수 있다. 연결된 모델에서 또 연결된 모델로 접근할 수도 있다. 만약 User
모델이 Classroom
이라는 모델과 연결되어 있으면 self.user.classroom.number
이런 식으로 Classroom
모델의 필드에도 접근 가능하다.
django-admin startapp 앱 이름
apps.py
라는 파일이 들어있다. 그 안에 class (앱)Config
가 있다. 이 클래스는 django.apps
로부터 앱의 configuration과 검사 기능을 저장하는 레지스트리를 불러오는 역할을 한다. (문서를 되는대로 번역한 것이라 잘못된 설명일 수도 있음...)settings.py
에 앱 configuration을 추가해야 한다. INSTALLED APPS = [...]
에 2번에서 본 configuration을 추가한다.INSTALEED APPS = [..., ..., users.apps.UsersConfig,]
와 같이 입력한다.model.py
에서 모델의 필드 등을 설정한다. 보통은 만드려는 모델 클레스를 생성하고 그 안에 필드를 입력하는 방식이다. 예를 들면 다음과 같다.class User(models.Model): # 일반적으로 django.db의 models 내 Model 클래스를 상속한다.
name = models.CharField()
python manage.py makemigrations (앱이름)
으로 변경된 앱의 모델 클래스 스키마를 반영한 migration을 만들어준다.(앱이름)은 특정 앱의 DB 스키마만 변경하고 싶을 때 입력하고, 여러 앱을 한번에 적용하려면 (앱이름)은 빼고 하면 된다.
python manage.py migrate
admin.py
에서 모델을 등록해야 한다. 모델 클래스 등록을 위해 models.py
를 불러온다. from . import models
models.py
내에 생성한 모델 클래스를 등록한다. 만약 user
라는 클래스가 있다면 다음과 같다.from . import models
@admin.register(models.user)
class UserAdmin(admin.UserAdmin): # 위와 두 줄 이상 띄어쓰면 안 된다.
pass
models.py
내에 생성한 모델 클래스를 등록한다. 위와 같은 user
클래스를 예시로 들면 다음과 같다.from . import models
admin.site.register(models.user)
어드민 패널에서는 모델 클래스의 __str__
혹은 모델 클래스명이 필드로 나온다. 예를 들어 Room
모델 클래스에서 아무런 __str__
을 등록하지 않았다면 Room 어드민 패널은 이렇게 보인다.
패널에서 보이는 정보를 수정하려면 그 앱의 admin.py
의 해당 모델 클래스에서 다음과 같이 편집한다.
list_display
에 원하는 필드명을 튜플 혹은 리스트로 준다.list_filter
에 필드명을 튜플 혹은 리스트로 준다.search_fileds
에 필드명을 튜플 혹은 리스트로 준다.예를 들어 Room
모델 클래스의 어드민 패널을 변경하려면 다음과 같이 admin.py
를 편집한다.
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
"""Room Admin Definition"""
list_display = (
"name",
"country",
"city",
)
list_filter = (
"city",
"country",
)
search_fields = (
"=city",
"^host__username", # FK 필드로 검색
)
이렇게 하면 어드민 패널은 이렇게 보인다.
search_fileds
옵션
search_fields
에 입력하는 필드명 앞에=
,^
를 붙여 검색 옵션을 줄 수 있다.
=
: 검색 문자열과 정확히 일치해야 한다.
^
: 검색 문자열로 시작해야 한다.
아무 옵션도 주지 않으면 substring으로 검색한다. 모든 옵션에서 대소문자는 구분하지 않는다.
search_fileds
에서 FK 필드로 검색
모델 내에서 FK의 필드를 사용할 때:self.FK모델명.FK필드명
(예:self.user.name
)
search_fields
에서 FK의 필드를 사용할 때:FK모델명__FK필드명
(예:user__name
)
filter_horizontal
로filter_horizontal
이다.admin.py
를 설정하면 Many to Many 관계인 모델을 아래와 같은 편리한 GUI로 편집할 수 있다.@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
filter_horizontal = (
"amenities",
"facilities",
"house_rules",
)
collapse
로 여러 필드 숨기기fieldsets
의 classes
에 collapse
를 넣으면 된다. filedsets
은 어드민 패널에서 보이는 필드를 그룹화할 때(fields
) 주로 사용하는데, classes
에 스타일 클래스를 줘서 그룹의 스타일을 바꿀 수 있다. 아래처럼 작성하면 해당 그룹이 숨겨져서 나온다.@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
fieldsets = (
(
(
"More About Space",
{
"classes": ("collapse",), # 그룹의 스타일
"fields": ( # 그룹화할 필드
"amenities",
"facilities",
"house_rules",
),
},
),
("Last Details", {"fields": ("host",)}),
)
classes
리스트
문서에 따르면classes
에는 CSS 클래스를 입력할 수 있다.collapse
와wide
는 기본적으로 주어지는 옵션이고, 그 외 본인이 만든 CSS 클래스도 사용할 수 있다.
위에서 list_display
에 원하는 필드 리스트를 넣어 어드민에서 해당 필드를 바로 볼 수 있다고 했다. 다만 여기에는 Many to Many 관계인 필드를 넣을 수 없다.
잊었을까 다시 보는 ForeignKey vs ManytoMany
ForeignKey 관계인 경우 외부 테이블에서 하나의 값만 가져오지만, ManytoMany에서는 여러 개의 값을 가져올 수 있다.
Many to Many 필드에 여러 개의 값이 있다면 그걸 전부 보여줄 수는 없으니 COUNT처럼 적당히 집계를 해서 보여주어야 한다.
집계 함수는 admin.py
의 원하는 클래스 내에서 만들면 된다. 어드민 내 함수는 self
, obj
라는 파라미터를 자동으로 가지는데 각각 클래스, 모델(DB 내 데이터)을 가리킨다.
def count_amenities(self, obj):
print(obj)
print(obj.amenities.all())
return None
위 함수를 넣고 어드민 패널을 실행하면 현재 DB에 있는 모델(obj
) 각각의 __str__
과 모델의 amenities 필드 값을 출력한다.
Room No.2
<QuerySet [<Amenity: Shower>]>
Room No.1
<QuerySet []>
QuerySet은 마치 SQL을 이용한 것처럼 DB의 모델 필드 값을 리스트로 반환한다. 이게 가능한 이유는 장고가 models.py
내 클래스를 SQL 없이 모델을 조회할 수 있게 QuerySet API를 제공하기 때문이다.
위에서 사용한 all()
외에도 count()
, filter()
등을 이용해 모델을 집계할 수 있다. 위의 경우에는 return obj.amenities.count()
를 하면 우리가 원하는대로 개수가 나온다.
위의 예제는 Many to Many로 연결된 여러 개의 값을 조회하는 방법이었다. 거꾸로 말하면 ForeignKey로 역참조된 경우에도 역으로 어떤 값에 연결되었는지 조회하는 것도 가능하다.
A에 B 필드를 FK로 연결할 경우, A는 무조건 하나의 B를 가지지만 B는 여러 A를 가질 수 있다(1:N). 다만 A의 어드민에서는 각 모델이 어떤 B 모델을 가지는지 볼 수 있지만, B의 어드민에서 각 모델이 어떤 A 모델을 가지는지는 확인할 수 없다. 여기서 위의 M:N 관계처럼 QerySet을 사용할 수 있다.
유저(B)가 방(A)에 FK로 연결된 경우를 가정해보자. Soo라는 유저(B의 모델)가 어떤 방을 가지고 있는지 확인하는 방법은 아래와 같다.
soo = User.objects.get(username="Soo")
soo.room_set.all()
이처럼 A_set
의 형식으로 어떤 A 모델에 연결되었는지 조회할 수 있다.
서울ICT 이노베이션 블록체인 기획강의 수강신청 성공했다!! 이제 8월까지... 월화수목금 TIL은 블록체인으로 대체되었다