모델 이해하기
모델은 데이터에 대한 단일 정보 소스이며 저장하려는 데이터의 필수 필드와 동작이 포함되어 있다.
모델 기초
- 각 모델은 django.db.models.Model의 하위클래스로 묶는 파이썬 클래스이다.
- 모델의 각 속성들은 데이터베이스 필드를 나타낸다.
- 장고는 자동으로 생성된 데이터베이스 액세스 API를 제공함
예제
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
- 테이블 이름은 myapp_person으로 저절로 정의됨. 그러나 재정의 가능
- id(기본 키) field는 자동으로 생성되지만 다른 이름으로 덮어질 수 있다. (기본 키는 관계형 DB에서 레코드의 식별자로 이용됨)
모델 사용하기
모델을 정의한 후에 INSTALLED_APPS에 패키지(앱) 이름을 추가해야함.
필드 옵션
null과 blank
blank = True면 값을 안넣어도 진행할 수 있게 함 -> form에서 빈값 전송
텍스트가 들어갈 수 있는 필드면 blank = True가 통하지만 그렇지 않은 몇몇의 필드에서는 에러를 발생시킨다.
특히 DateField는 빈 텍스트를 저장할 수 없기 때문에 null=True를 해주어야함
blank= True는 장고에서 그냥 처리가능 null = True는 데이터 베이스에서 Null값을 받을 수 있게 바꾸는 것이므로 migrate를 해주어야함
choices
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
primary_key
primary_key가 True면 기본 키가 모델에 사용되는 것을 의미한다. 하지만 설정하지 않더라도 자동으로 IntegerField가 추가되어 기본 키가 설정 될 것이다.
pk는 읽기만 가능하다. 만약에 바꾸고 값을 저장한다면 새로운 객체가 만들어진다.
unique
유일한 값을 가지게 하는 속성
Verbose field names
ForeignKey, ManyToManyField, OneToOneField를 제외한 필드 타입의 선택적 첫번째 인수 ex)’이름’ -> 자세한 이름 속성
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField('이름', max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
ForeignKEy, ManyToManyField, OneToOneField의 필드 타입은 항상 첫 번째 인수로 모델의 클래스를 받기 때문에 verbose_name 키워드 인자로 받는다.
poll = models.ForeignKey(
Poll,
on_delete=models.CASCADE,
verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
verbose_name="related place",
)
Relationships
관계형 데이터의 힘은 테이블을 서로 연관시키는 데 있다. Django는 세가지 관계형 데이터베이스를 정의하는 방법을 제공함
- many-to-one
- many-to-many
- one-to-one
Many-to-one relationships
다대일 관계는 ForeignKey를 사용하여 정의할 수 있음. 클래스 속성으로 추가되는 걸로 여느 다른 필드 타입처럼 사용될 수 있다.
ForeignKey는 모델과 관련한 위치인자를 인수로 받는다.
class Person(models.Model):
# 자기 자신을 다대일로 연결하는 필드
# 비어있어도 무관, 연결된 객체가 삭제되어도 함께 삭제되지 않는다.
# 해당 필드를 비움
name = models.CharField(max_length=60)
teacher = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
null=True,
blank=True,
)
def __str__(self):
return f'{self}'
Many-to-many relationships
ManyToManyField를 이용해서 many-to-many 관계를 정의할 수 있다.
마찬가지로 위치인자를 받는다.
예를 들어서 토핑은 여러가지 피자 메뉴에 들어갈 수 있고 피자 메뉴에는 여러가지 토핑이 들어갈 수 있다. 이와 같은 관계를 many-to-many관계라고 한다.
class Topping(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
def __str__(self):
return self.name
쉘에서 연습해보기
from many_to_many.models import Topping, Pizza
>>> cheese = Topping.objects.create(name='치즈')
>>> pepperoni = Topping.objects.create(name='페페로니')
>>> ham = Topping.objects.create(name='햄')
>>> pineapple = Topping.objects.create(name='파인애플')
>>> shrimp = Topping.objects.create(name='새우')
>>> cheese_pizza = Pizza.objects.create(name='치즈피자')
>>> cheese_pizza.toppings.add(cheese)
# many to many field에서 내용을 추가할 때는 save()가 필요 없다. 넣자마자 바로 save됨
>>> pepperoni_pizza = Pizza.objects.create(name= '페페로니 피자')
>>> pepperoni_pizza.toppings.add(cheese)
>>> pepperoni_pizza.toppings.add(pepperoni)
>>> master_pizza = Pizza.objects.create(name='피자왕')
>>> master_pizza.topping.add(cheese, pepperoni, shrimp, ham, mushroom, pineapple)
Extra fields on many-to-many relationships
그냥 단순히 피자와 토핑의 관계같은 단순한 다대다관계를 다루려면 standard ManyToManyField를 사용하면 그만이다. 하지만 두 모델 간의 연관된 정보가 필요할 경우도 있다.
예를 들면, 음악가들이 속해있는 음악단을 조사하는 경우를 생각해보자. 이러한 다대다 경우는 음악가와 음악단 사이의 입단날짜와 같은 세부정보가 존재할 수 있다.
이러한 경우에는 그냥 through를 사용한 중급 다대다관계 모델을 사용하면 된다.
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
이렇게 멤버쉽 클래스에 각 각 ForeignKey로 확실하게 두 모델의 관계를 정의할 수 있다.
쉘에서 연습해보기
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
One-to-one relationships
일대일 관계의 예를 먼저 들면 장소(Place)에 대한 데이터베이스를 생성한다고 할 때, 주소, 전화번호와 같은 고유한 것들이 함께 고려된다.
만약 레스토랑의 데이터베이스를 구축하기를 원한다면 레스토랑 모델에서 자신을 반복하고 해당 필드를 복제하는 대신 장소(Place)에 OneToOneField를 걸 수 있다.
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self):
return f'{self.name} the place'
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key = True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self):
return f'{self.place.name} the restaurant'
class Waiter(models.Model):
restaurant = models.ForeignKey(
Restaurant,
on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name} the waiter at {self.restaurant}'
쉘에서 실습해보기
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
장소와 레스토랑을 생성한다.
레스토랑에서 장소에 접근할 수 있다.
>>> r.place
<Place: Demon Dogs the place>
장소에서도 레스토랑에 접근할 수 있다.
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
할당 개념으도 장소를 설정할 수 있다. 장소는 레스토랑의 primary key로 있기 때문이다(?)
You can query the models using lookups across relationships: (검색을 이용해 관계들 사이를 뛰어넘어 질의할 수 있다?)
>>> Restaurant.objects.get(place=p1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place__pk=1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.filter(place__name__startswith="Demon")
<QuerySet [<Restaurant: Demon Dogs the restaurant>]>
>>> Restaurant.objects.exclude(place__address__contains="Ashland")
<QuerySet [<Restaurant: Demon Dogs the restaurant>]>
Comments