1. Django Tutorial(Airbnb) - ForeignKey & ManyToManyField
43945 단어 django tutorialdjango tutorial
🌈 ForeignKey & ManyToManyField
🔥 ForeignKey
🔥 ManyToManyField
🔥 Sting 형태로 테이블 연결
🔥 set을 통한 접근 & related_name
1. ForeignKey
- ForeignKey는 한 테이블의 필드를 기준으로 다른 모델의 테이블을 연결시키는 기능으로 ForeignKey가 포함된 테이블을 '자식 테이블'이고, ForeignKey를 통해 참조할 테이블을 '부모 테이블'이라 해요.
- ForeignKey는 '자식 테이블'의 필드 값이 '부모 테이블'의 Primary Key를 참조함으로써 일대다 관계로(many-to-one) 테이블을 연결하는데, '부모 테이블'의 한 object가 자신을 참조하는 '자식 테이블'의 여러 object와 연동되어 DB를 효과적으로 관리할 수 있어요.
1) ForeignKey 란?
- 아래 코드를 보면, 여러개의 객실 정보를 저장하는 Room 테이블의 'host' 필드가 User 테이블의 Primary Key를 참조 함으로써 Room 테이블의 object들이 어떤 사용자와 연결 지을지 결정합니다.
- ForeignKey 사용 방법
- 🔎 필드명 = ForeignKey(참조할 모델, on_delete="")
- 아래 코드에서 host 필드는 User 테이블을 ForeignKey로 참조하고 있고, room_type 필드는 같은 Model에 있는 RoomType 테이블을 참조하고 있어요.
from django.db import models from django_countries.fields import CountryField from core import models as core_models from users import models as user_models # Create your models here. class AbstractItem(core_models.TimeStampedModel): """AbstractItem Object Definition""" name = models.CharField(max_length=80) class Meta: abstract = True def __str__(self): return self.name class RoomType(AbstractItem): """Room Type Model Definition""" pass class Room(core_models.TimeStampedModel): """Room Model Definifion""" name = models.CharField(max_length=140) description = models.TextField() city = models.CharField(max_length=80) country = CountryField() price = models.IntegerField() address = models.CharField(max_length=140) guests = models.IntegerField() beds = models.IntegerField() bedrooms = models.IntegerField() baths = models.IntegerField() check_out = models.TimeField() check_in = models.TimeField() instant_book = models.BooleanField(default=False) host = models.ForeignKey(user_models.User, on_delete=models.CASCADE) # 👈 ForeignKey room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE, null=True) # 👈 ForeignKey def __str__(self): return self.name
2) on_delete 옵션
- ForeignKey 통해서 생성된 객실이 어떤 한 사용자를 가르키고 있는데, 만일 사용자가 탈퇴를 한다면 해당 객실의 데이터를 어떻게할지 결정하는 것이 on_delete 옵션의 기능이에요.
- CASCADE : 참조 대상인 부모(사용자)를 삭제하면, 참조하고 있는 자식(객실)을 자동으로 삭제
- 🔎 on_delete=models.CASCADE
- PROTECT : 참조 중인 자식(객실)을 모두 삭제하기 전에는 참조 대상인 부모(사용자)를 삭제 할 수 없도록 보호
- 🔎 on_delete=models.PROTECT
- SET_NULL : 참조 대상인 부모(사용자)를 삭제하면, 참조 중인 자식(객실)은 참조값 Null을 가지고 존재
- 🔎 on_delete=models.SET_NULL
- Default : 참조 대상인 부모(사용자)를 삭제하면, 참조 중인 자식(객실)은 설정한 Default값과 연결
- 🔎 on_delete=models.SET_DEFAULT
2. ManyToManyField
1) ManyToManyField 란?
- ManyToManyField는 다대다 관계(many-to-many)로 테이블을 연결하고자 할 때 사용해요.
- 예를 들어, 1개의 게시글에 여러 개의 tag가 달릴 수 있고, 또한 어떤 한 tag는 여러 개의 게시글에서 사용될 때 사용해요.
- ManyToManyField 관계를 필드를 생성하게 되면 관계 연결을 위한 중간 테이블(Intermediate Table)을 Django에서 자동으로 생성합니다.
2) room/models.py
- ManyToManyFiel 사용 방법
- 🔎 필드명 = ManyToManyField(참조할 모델, blank=True)
from django.db import models from django_countries.fields import CountryField from core import models as core_models from users import models as user_models # Create your models here. class AbstractItem(core_models.TimeStampedModel): """AbstractItem Object Definition""" name = models.CharField(max_length=80) class Meta: abstract = True def __str__(self): return self.name class RoomType(AbstractItem): """Room Type Model Definition""" pass class Amenity(AbstractItem): """Amenity Model Definition""" pass class Facility(AbstractItem): """Facility Model Definition""" pass class HouseRule(AbstractItem): """HouseRule Model Definition""" pass class Room(core_models.TimeStampedModel): """Room Model Definifion""" name = models.CharField(max_length=140) description = models.TextField() city = models.CharField(max_length=80) country = CountryField() price = models.IntegerField() address = models.CharField(max_length=140) guests = models.IntegerField() beds = models.IntegerField() bedrooms = models.IntegerField() baths = models.IntegerField() check_out = models.TimeField() check_in = models.TimeField() instant_book = models.BooleanField(default=False) host = models.ForeignKey(user_models.User, on_delete=models.CASCADE) room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE, null=True) amenities = models.ManyToManyField(Amenity, blank=True) # 👈 ManyToManyField facilities = models.ManyToManyField(Facility, blank=True) # 👈 ManyToManyField house_rule = models.ManyToManyField(HouseRule, blank=True) # 👈 ManyToManyField def __str__(self): return self.name
3) room/admin.py
- Admin Panel에 나타나게 하기 위해서는 아래처럼 admin 등록을 진행시켜주어야 하죠,, 이를 통합하여 작성할 수 도 있습니다.
from django.contrib import admin from . import models # Register your models here. @admin.register(models.RoomType) class ItemAdmin(admin.ModelAdmin): pass @admin.register(models.Amenity) class AmenityAdmin(admin.ModelAdmin): pass @admin.register(models.Facility) class FacilityAdmin(admin.ModelAdmin): pass @admin.register(models.HouseRule) class HouseRuleAdmin(admin.ModelAdmin): pass @admin.register(models.Room) class RoomAdmin(admin.ModelAdmin): pass
- 단, 테이블이 비슷한 특징을 갖고 있고 추후 개별적인 Custom이 필요없을 때는 Admin을 통합하여 등록할 수 있어요:)
from django.contrib import admin from . import models # Register your models here. @admin.register(models.RoomType, models.Amenity, models.Facility, models.HouseRule) class ItemAdmin(admin.ModelAdmin): pass @admin.register(models.Room) # 👈 별도의 Custom을 적용시킬 테이블을 통합시키지 않아요:) class RoomAdmin(admin.ModelAdmin): pass
3. Sting 형태로 테이블 연결
- Python은 코드를 위에서 아래로 방향으로 읽어나가기 때문에 참조할 Class가 아래 있으면 읽어오지 못한다는 문제가 있어요.
from django.db import models from core import models as core_models from users import models as user_models # Create your models here. class Photo(core_models.TimeStampedModel): """Photo Model Definition""" caption = models.CharField(max_length=80) file = models.ImageField() room = models.ForeignKey(Room, on_delete=models.CASCADE) # 👈 바로 아래 Room을 인식못함 class Room(core_models.TimeStampedModel): """Room Model Definifion""" name = models.CharField(max_length=140) description = models.TextField() city = models.CharField(max_length=80) country = CountryField() price = models.IntegerField() address = models.CharField(max_length=140) guests = models.IntegerField() beds = models.IntegerField() bedrooms = models.IntegerField() baths = models.IntegerField() check_out = models.TimeField() check_in = models.TimeField() instant_book = models.BooleanField(default=False) host = models.ForeignKey(user_models.User, on_delete=models.CASCADE) room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE, null=True) amenities = models.ManyToManyField(Amenity, blank=True) facilities = models.ManyToManyField(Facility, blank=True) house_rule = models.ManyToManyField(HouseRule, blank=True) def __str__(self): return self.name
- 이런 경우에, string으로 변환하여 Model을 연결시키면 import를 하지 않아도 Django에서 해당 Class를 스스로 찾고, 참조할 Class가 아래 있더라도 Django에서 알아서 처리합니다:)
from django.db import models from core import models as core_models # from users import models as user_models # 👈 필요 없음 # Create your models here. class Photo(core_models.TimeStampedModel): """Photo Model Definition""" caption = models.CharField(max_length=80) file = models.ImageField() room = models.ForeignKey("Room", on_delete=models.CASCADE) # 👈 string으로 연결 class Room(core_models.TimeStampedModel): """Room Model Definifion""" name = models.CharField(max_length=140) description = models.TextField() city = models.CharField(max_length=80) country = CountryField() price = models.IntegerField() address = models.CharField(max_length=140) guests = models.IntegerField() beds = models.IntegerField() bedrooms = models.IntegerField() baths = models.IntegerField() check_out = models.TimeField() check_in = models.TimeField() instant_book = models.BooleanField(default=False) # 👇 string으로 연결 host = models.ForeignKey("users.User", on_delete=models.CASCADE) room_type = models.ForeignKey("RoomType", on_delete=models.CASCADE, null=True) amenities = models.ManyToManyField("Amenity", blank=True) facilities = models.ManyToManyField("Facility", blank=True) house_rule = models.ManyToManyField("HouseRule", blank=True) def __str__(self): return self.name
3. set을 통한 접근 & related_name
1) set을 통한 접근
- ForeignKey로 어떤 테이블 가르킬 경우, 자식 테이블의 필드값으로 부모테이블로 접근이 가능해요!
- 즉, ForeignKey로 부모 테이블를 참조중이기 때문에 해당 object의 모든 필드에 접근이 가능합니다.
- _set은 반대로 그 object에서 자식 테이블의 필드에 접근하는 기능이에요.
- Room 모델에 있는 host 필드(rooms/models.py)가 ForeignKey를 통해 User 테이블을 가르키면, User 모델에 각 object에서 "[모델명]_set"으로 자신을 가르키는 모든 element에 접근이 가능합니다.
- 즉, _set는 자신을 참조하고 있는 object로 접근하는 기능이에요:)
2) related_name
- 필드 속성으로 related_name에 값을 지정하면, _set으로 접근하는 대신 지정한 값으로 접근이 가능해요.
- 🔎 host = models.ForeignKey("users.User", related_name="rooms", on_delete=models.CASCADE)
class Room(core_models.TimeStampedModel): """Room Model Definifion""" name = models.CharField(max_length=140) description = models.TextField() city = models.CharField(max_length=80) country = CountryField() price = models.IntegerField() address = models.CharField(max_length=140) guests = models.IntegerField() beds = models.IntegerField() bedrooms = models.IntegerField() baths = models.IntegerField() check_out = models.TimeField() check_in = models.TimeField() instant_book = models.BooleanField(default=False) host = models.ForeignKey( "users.User", related_name="rooms", on_delete=models.CASCADE ) room_type = models.ForeignKey( "RoomType", related_name="rooms", on_delete=models.CASCADE, null=True ) amenities = models.ManyToManyField("Amenity", related_name="rooms", blank=True) facilities = models.ManyToManyField("Facility", related_name="rooms", blank=True) house_rule = models.ManyToManyField("HouseRule", related_name="rooms", blank=True) def __str__(self): return self.name
- ManyToManyField 또한 _set을 이용하여 자신을 가르키고있는 object로 접근할 수 있어요:)
Author And Source
이 문제에 관하여(1. Django Tutorial(Airbnb) - ForeignKey & ManyToManyField), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jewon119/Django-기초-ForeignKey-ManyToManyField저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)