Computer Science/BackEnd

장고 공식 문서 #2-1 | Using Django : Models and databases

토마토. 2022. 9. 5. 20:19

Django documentation contents | Django documentation | Django (djangoproject.com)

 

Django documentation contents | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

모델과 데이터베이스 - 모델
빠른 사례

장고에서 모델은 데이터에 대해 알 수 있는 단일 정보 소스이다. 

모델에 데이터의 필드와 동작(매소드)를 정의하고, 이 모델은 데이터베이스 테이블에 매핑된다. 

기본적으로 모델은 django.db.models.Model을 상속받아 정의하는 파이썬 클래스이다. 

모델 내부 변수는 데이터베이스 필드(열)을 나타낸다. 

 

모델에 대해 장고는 자동으로 데이터베이스 엑세스 API를 제공한다. 이를 쿼리를 만들 때 사용한다. 

 

<models.py>에 정의

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

위 예시에서 Person이라는 모델을 정의하였다. Person에는 first_name, last_name이라는 필드가 있다. 

 

이 모델을 makemigrations, migrate을 해주면, 

만들어지는 데이터베이스 테이블은 다음과 가다. 

CREATE TABLE myapp_person (
    "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, 
    "first_name" varchar(30) NOT NULL, 
    "last_name" varchar(30) NOT NULL,
);
  • 테이블명은 자동으로 생성되지만 수정 가능
  • 필드가 자동으로 추가됨
  • 지정한 RDBS에 따라 SQL 구문이 달라짐

 

모델 사용하기

모델을 정의한 뒤에는 장고에게 해당 모델을 사용할 것이라고 말해야 한다. 

  • step 1. 일단 settings.py에서 INSTALLED_APPS 목록에 'myapp'을 추가해준다. 
  • step 2. managy.py makemigrations을 수행해준다. 
  • step 3. managy.py migrate를 수행한다. 
모델 필드

모델에서 가장 중요한 부분. 필드는 클래스 속성으로 지정된다. 

이때 모델 API와 충돌하는 clean, save, delete 같은 이름을 사용하지 않도록 유의해야 한다. 

from django.db import models

class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

 

  • 필드 타입

모델의 각 필드는 Field 클래스의 적절한 인스턴스여야 한다.

Model field reference | Django documentation | Django (djangoproject.com)

이 필드를 이용해서 데이터베이스가 어떤 데이터로 저장해야하는지 알 수 있고, 

HTML 위젯 태그를 결정할 수 있다. 

 

다음 링크(Model field reference | Django documentation | Django (djangoproject.com))에 들어가면, 모델 필드의 모든 데이터타입을 확인할 수 있다. 

 

  • 필드 옵션

필드 데이터타입 안에 인수가 필요한 경우가 있다. 

예를 들면, CharField에는 max_length 인수가 필수적. 

 

모든 필드에 사용되는 공통 인수도 있다. 예를 들면, null, blank, choice가 있다. 

이때 blank는 유효성 검사와 관련이 있어서, blank=True로 설정해둔 경우에만 빈 값을 입력하는걸 허용한다. 

choice는 필드의 인수로 사용할 수 있는 튜플 시퀀스이다. 

만약 choice 옵션을 가하면, 기본 양식이 선택 항목으로 선택이 제한된다. 

YEAR_IN_SCHOOL_CHOICES = [
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
]

 

Choice 항목을 사용하는 방식은 다음 사례로 알아볼 수 있다. 

class Customer(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)

class Customer에서 SHIRT_SIZES라는 choice를 만들고, shirt_size라는 필드에서 choice를 SHIRT_SIZES 튜플에 제한을 둔 것이다. 

 

실제 객체를 생성할 때에는

$ python manage.py shell
>>> p = Customer(name="Fred", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'

DB안에 저장되는 이름과 실제 display해주는 이름이 다르다는 걸 알 수 있다. 

 

보다 간결하게 정의할 수도 있다.

class Runner(models.Model):
    MedalType = models.TextChoices('MedalType', 'Gold Silver Bronze')
    name = models.CharField(max_length=60)
    medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)

TextChoices 타입을 이용해서 더 간결하게 정의해주었다.

class Fruit(models.Model):
    name = models.CharField(max_length=100, primary_key=True)

꼭 primary_key=True를 설정할 필요가 없다.

 

  • 자동 기본 키 필드

장고는 모든 모델에 auto-incrementing primary key를 제공한다. 

id = models.BigAutoField(primary_key=True)

사용자가 지정한 기본 키를 지정하려면, 필드에서 primary_key=True)를 지정해주어야 한다. 

 

  • 자세한 정보를 표시하는 필드 이름

각 필드의 타입은 첫번째 위치 인수를 디테일한 정보를 표시하는 이름으로 사용한다. 

직접 지정해주지 않을 경우, 변수 이름을 변형해서 verbose name을 설정해준다. 

class Customer(models.Model):
    SHIRT_SIZES = (
        ('S', 'Small'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    name = models.CharField(max_length=60)
    # 이때는 verbose field name이 person's first name
    first_name = models.CharField("person's first name", max_length=30)
    # 이때는 first name
    first_name = models.CharField(max_length=30)

예외적으로 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",
)

 

  • 관계

 

  • ManyToOne Relation
    • django.db.models.ForeignKey를 사용한다. 
    • ManyToOne의 예시 : Manufacturer와 Car 모델의 관계
    • Manufacturer는 여러 개의 Car를 가질 수 있지만, Car은 하나의 Manufacturer만을 가질 수 있다. 
    • 이때 Car에 연결된 Manufacturer를 ForeignKey를 이용하여 연결해준다. 
from django.db.import models
class Manufacturer(models.Model):
    pass
class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
  •  

 

 

  • ManyToMany Relation
    • django.models.ManyToManyField를 사용
    • Field에 모델의 클래스 속성을 포함시킨다. 
from django.db import models
class Topping(models.Model):
    pass
class Pizza(models.Model):
    toppings = models.ManyToManyField(Topping)

아직 정의되지 않은 모델에 대한 관계를 만들어줄 수 있다. 두 개의 모델 중 하나에만 ManyToManyField 필드를 만들어주어야 한다.

 

ManyToManyField를 효과적으로 관리하기 위해 중간자 역할을 하는 모델을 지정해줄 수도 있다. 

from django.db import models
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)

위에서 중간적인 모델은 바로 Membership이다. ManyToMany 관계인 모델 Group에는 ManyToManyField인 members를 정의해준다. MEmbership 중간 모델에는 소스 모델에 대해 ForeignKey를 하나씩 정의해준다. 

 

실제 인스턴스를 만드는 방법은 다음과 같다. 

ringo = Person.objects.create(name = "ringo")
paul = Person.objects.create(name = "paul")
beatles = Group.objects.create(name = "beatles")
m1 = Membership(person = ringo, group = beatles, 
	date_joined=date(1962,8,16),
    invited_reason="drummer.")
m1.save()
beatles.members.all()
ringo.group__set.all()
m2 = Membership(person = paul, group = beatles, 
	date_joined=date(1962,8,1),
    invited_reason="band.")
beatles.members.all()

 

  • OneToOne Relation
  • 파일 간 모델

다른 파일에 있는 모델을 가져올 때

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    zip_code = models.ForeignKey(
        ZipCode, 
        on_delete=models.SET_NULL, 
        blank=True, 
        null=True,
    )

 

  • 필드 이름 제한
  • 사용자 지정 필드 유형
from django.db.import models
class Manufacturer(models.Model):
    pass
class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)

 

메타 옵션

모델 클래스 내에 Meta 클래스를 다시 정의하여 모델의 매타 데이터를 정의할 수 있다. 

class Ox(models.Model):
    horn_length = models.IntegerField()
    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"