본문 바로가기
개발/AWS

Django 앱 만들기 - abstract class, ForeignKey, __str__, ManyToManyField

by ny0011 2021. 1. 19.
반응형

1) abstract class 만들기

다른 앱에서 사용하는 공통 필드들을 한 곳에 모아서 상속 받아서 사용하면 편하다

Abstract base classes are useful when you want to put some common information into a number of other models.

 

1. models.py에 다른 곳에서 import할 class를 정의해준다

2. 그 클래스 내부에 Meta class를 만든다

3. abstract = True

=> 이 클래스는 DB가 생성되지 않고 얘를 상속 받는 곳에서 DB가 만들어진다

class TimeStampedModel(models.Model):

    """ Time Stamped Model """

    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

docs.djangoproject.com/en/3.1/topics/db/models/#abstract-base-classes

 

* DateTimeField() 옵션

auto_now_add : 모델을 저장할 때 자동으로 현재 날짜를 저장

auto_now : 모델을 생성할 때마다 수시로 날짜를 업데이트

docs.djangoproject.com/en/3.1/ref/models/fields/#datefield

 

* model의 meta class 옵션들

verbose_name_plural : django admin 화면에서 보여질 이름. 아무것도 안하면 verbose_name에 's'를 붙임

verbose_name : model 이름

ordering : 정렬 기준, -가 붙으면 내림차순, 없으면 오름차순

class RoomType(AbstractItem):

    """ RoomType Model Definition """
    class Meta:
        verbose_name = "Room Type"
        ordering = ["name", "-created"]
        
 class Facility(AbstractItem):

    """ Facility Model Definition """
    class Meta:
        verbose_name_plural = "Facilities"

 

 

2) ForeignKey 

다른 모델에서 정의한 필드를 사용하고 싶을 때 ForeignKey 설정을 한다

일대다 관계(many-to-one relation) : user 1명은 여러 개의 room을 가질 수 있음. room은 user 1명만 가질 수 있다

 

ex) user에 있는 필드를 room에서 사용하고 싶음

 

1. user의 models를 import(이름이 겹치니 변경해준다)

2. models.ForeignKey() 안에 user_models.User 를 넣어준다

-> ForeignKey에는 다른 테이블의 id가 들어감(user의 id가 들어감)

 

1. 에서 users의 models를 import하는 대신 string type으로 "users.User"로 해주면 Django가 메소드를 찾아줌

from core import models as core_models
from users import models as user_models

class Room(core_models.TimeStampedModel):

	""" Room Model Definition """
    
	#host = models.ForeignKey(user_models.User, on_delete=models.CASCADE)
    host = models.ForeignKey("users.User", on_delete=models.CASCADE)
    room_type = models.ForeignKey(RoomType, on_delete=models.SET_NULL, null=True)

docs.djangoproject.com/en/3.1/ref/models/fields/#foreignkey

 

* ForeignKey로 DB의 table이 연결되어 있으면 review -> room -> user로 몇 단계 건너건너 값을 불러올 수 있다

    def __str__(self):
        return f'{self.room.host.username} - {self.review}'

* on_delete : ForeignKey가 삭제될 때 어떤 행동을 할지 옵션을 줄 수 있다

- CASCADE : ForeignKey가 삭제되면 이 ForeignKey를 가진 테이블도 삭제함

- PROTECT : ForeignKey와 연결된 테이블을 삭제하기 전 까진 ForeignKey를 삭제할 수 없음

- RESTRICT(3.1에서 새로 생김) : RestrictedError를 발생 시켜서 연관된 object의 삭제를 막음(??)

CASCADE 관계로 되어있고 PROTECT로 해둔 것이 있을 때 PROTECT된 것도 같이 삭제하고 싶을 때 쓰는듯

class Artist(models.Model):
    name = models.CharField(max_length=10)

class Album(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)

class Song(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    album = models.ForeignKey(Album, on_delete=models.RESTRICT)

위의 관계일 때 아래처럼 설정함

artist 1 ~ album 1~ song1, song2  

artist 2 ~ album 2

 

1) album 1을 삭제 -> song과 RESTRICT 관계이므로 RestrictedError 발생

2) artist 2를 삭제 -> song과 artist 관계가 없어서(그런 걸로 추측...) RestrictedError 발생

3) artist 1을 삭제 -> album1, song1, song2가 함께 삭제됨

code.djangoproject.com/ticket/27272

 

- SET_NULL : ForeignKey가 삭제되면 ForeignKey의 값을 null로 설정(null=True로 설정해주자)

- SET_DEFAULT : ForeignKey가 삭제되면 ForeignKey의 default 값으로 설정(ForeignKey의 default값을 미리 설정해둬야 사용 가능)

 

ex) user : aa, room : r1, r2 .. 

- CASCADE : r1, r2 모두 삭제됨

- PROTECT : r1, r2 모두 삭제 되기 전까지 삭제 안됨

 

 

3) __str__ 

python의 class는 __init__, __str__ 등 메소드가 미리 정의되어 있다

__str__는 print(), str() 등 class의 instance를 출력할 때 불려짐

-> Django에서 보통 str(obj) 형태로 class를 출력할 때가 많으니 __str__로 어떤 내용을 보여줄 지 적어두면 좋다

from core import models as core_models
from users import models as user_models

class Room(core_models.TimeStampedModel):

	""" Room Model Definition """
    
    def __str__(self):
        return self.name

docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.__str__

realpython.com/lessons/how-and-when-use-str/

 

4) ManyToManyField : 다대다 관계

room마다 room type을 여러 개 설정할 수 있음, room type도 여러 개의 room을 가질 수 있다

-> 이럴 땐 다대다 관계를 적용함

 

models.py에 RoomType을 정의하고

- AbstractItem을 따로 만든 이유는 room type, amenity에 공통으로 들어가는 필드를 묶어둠

class AbstractItem(core_models.TimeStampedModel):

    """ Abstract Item """

    name = models.CharField(max_length=80)

    class Meta:
        abstract = True

    def __str__(self):
        return self.name


class RoomType(AbstractItem):
    pass
    
# Room에서 RoomType을 다대다 연결로 사용    
class Room(core_models.TimeStampedModel):

    room_type = models.ManyToManyField(RoomType, blank=True)

 

admin 패널에서 RoomType을 조작할 수 있게 등록함. 여러 개를 한번에 등록해도 되는듯!

@admin.register(models.RoomType, models.Facility, models.Amenity, models.HouseRule)
class ItemAdmin(admin.ModelAdmin):
    pass

docs.djangoproject.com/en/3.1/ref/models/fields/#manytomanyfield

docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/

happyer16.tistory.com/entry/Spring-JPA-%EB%8B%A4%EB%8C%80%EB%8B%A4-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%A3%BC%EC%9D%98-Many-To-Many

 

댓글