모델 클래스는 속성과 메소드를 가집니다. 테이블의 컬럼은 모델 클래스의 속성으로 정의합니다.
Meta 내부 클래스를 정의해 모델에 대한 메타데이터를 정의할수 있습니다. 테이블의 필드는 모델 클래스의 속성으로 정의하고 필드 이외에 항목은 Meta 내부 클래스의 속성으로 정의해 구분하고 있습니다. 아래는 많이 사용하는 Meta 내부 클래스 속성입니다.
모든 모델은 반드시 Manager속성을 가져야합니다. 모델을 정의할 때 매니저를 명시하지 않는면 디폴트 이름은 objects가 됩니다. 또한 Manager속성은 모델 클래스를 통해서만 액세스 할 수 있고 모델 객체를 통해서는 액세스 할수 없습니다.
Album.objects.all()
Album => 모델 클래스
objects => 매니저 속성명
all() => 매니저 클래스의 메소드
위 문장은 QuerySet객체를 반환합니다. QuerySet클래스의 메소드와 Manager 클래스의 메소드는 동일합니다. 그리고 매니저 속성을 여러개 정의 할 수 있습니다.
class SecondAlbumManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(owner__username = 'ksksk')
class Album(models.Model):
name = models.CharField(max_length=30)
description = models.CharField('one line', max_length=100, blank=True)
objects = models.Manager() # 디폴트 매니저
second_objects = SecondAlbumManager() # 추가 매니저
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('photo:album_detail', args=(self.id,))
장고는 테이블 간 일대다 관계를 정의하기 위해 ForeignKey필드를 사용합니다. ForeignKey필드는 One모델이 아닌 Many모델에 정의합니다.
하나의 앨범에 여러개의 코멘트인 관계를 모델로 작성한다고 가정합니다.
Album <-> AlbumComment 일대다 관계입니다.
class Album(models.Model):
name = models.CharField(max_length=30)
description = models.CharField('one line', max_length=100, blank=True)
objects = models.Manager() # 디폴트 매니저
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('photo:album_detail', args=(self.id,))
class AlbumComment(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
album = models.ForeignKey(Album, on_delete=models.CASCADE, verbose_name='album', blank=True, null=True)
생성하고 따로 지정
>>> album1 = Album.objects.first()
>>> album1
<Album: 스크린샷>
>>> comment1 = AlbumComment()
>>> comment1.title = 'album title'
>>> comment1.content = 'noob'
>>> comment1.save()
>>> album.albumcomment_set.add(comment1)
생성하면서 지정
>>> album1 = Album.objects.first()
>>> album1
<Album: 스크린샷>
>>> album1.albumcomment_set.create(title='tt', content='qq')
<AlbumComment: AlbumComment object (4)>
>>> album1.albumcomment_set.count()
ManyToManyField필드 정의는 두 모델 중 어느쪽이라도 가능하지만, 한쪽에만 정의해야 하면 양쪽에 정의하면 안 됩니다.
한 앨범이 여러개의 출판물에 게시되고, 또 한 출판물에는 여러 개의 앨범이 게시는 관계를 가정합니다.
class Album(models.Model):
name = models.CharField(max_length=30)
description = models.CharField('one line', max_length=100, blank=True)
objects = models.Manager() # 디폴트 매니저
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('photo:album_detail', args=(self.id,))
class Publication(models.Model):
title = models.CharField(max_length=30)
albums = models.ManyToManyField(Album)
>>> p1 = Publication(title='aa')
>>> p1.save()
>>> album1 = Album.objects.first()
>>> album1.publication_set.add(p1)
테이블 간에 일대일 관계를 맺기 위해서는 모델 필드를 정의할 때 OneToOneField 필드 타입을 사용하면 됩니다.
하나의 장소에 하나의 식당만 존재한다고 가정해봅시다.
장소는 Place 식당은 Restaurant 입니다.
class Place(models.Model):
name = models.CharField(max_length=10)
def __str__(self):
return f"Place-{self.name}"
class Restaurant(models.Model):
place = models.OneToOneField(Place, on_delete=models.CASCADE)
name = models.CharField(max_length=10)
def __str__(self):
return f"Restaurant-{self.name}"
>>> p1 = Place(name='plll')
>>> p1.save()
>>> r1 = Restaurant.objects.create(place=p1, name='resres')
>>> r1.place
<Place: Place-plll>
>>> p1.restaurant
<Restaurant: Restaurant-resres>
매니저 중에서 모델 간 관계에 대한 기능 및 데이터베이스 쿼리를 담당하는 클래스를 관계매니저라고 합니다.
모델 간 관계는 3가지가 있는데, 그중 일대다, 다대다 관계에서만 관계 매니저를 사용 됩니다.
클래스를 `__dict__
로 속성값을 출력하면 여러 관계 매니저를 확인 할 수 있습니다.
Album.__dict__
'photo': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7f7f367ea908>,
'albumcomment_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7f7f367ead30>,
'publication_set': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x7f7f350e5630>})
찾아보니 비슷한 기능으로 GenericForeignKey가 있습니다.