본문 바로가기

참고문서(번역?)/파이썬

Models: 데이터베이스와 연결하는 넘


두 번째 번역 중인 글입니다.

이제는 머리가 안돌아가서... 이렇게라도 하면 좀 익혀질까 하는 생각이 드네요.. ^^


처음 번역한 문서에 링크가 되어 있는 것들을 하나씩 추가로 해보려고 합니다.

출처: Django 공식싸이트의 어떤 문서(https://docs.djangoproject.com/en/1.10/topics/db/models/)

한번 시작해 볼까요? 저작권에 문제가있다면 바로 삭제하겠습니다.

번역은 기냥 제가 편한데로... 어떨 땐 의역, 어떨 땐 직역 ^^

불편하더라도 양해 바랍니다.


모델

model이란 데이터를 정의하는 정보를 담고 있는 모듈이다.  이 것은 필수 필드와 데이터 조작에 대한 정의을 포함하고 있다. 일반적으로 각 모델은 단일 데이터베이스 테이블과 매핑된다.

기본 사항:

  • 각 각의 모델은 Python 클래스로서 django.db.models.Model의 서브클래스이다.
  • 모델 내의 각 속성(attribute)은 하나의 데이터베이스 필드를 나타낸다.
  • 이러한 모든 것들을 가지고, Django는 자동으로 생성된 데이터베이스 접근 API를 제공한다(쿼리만들기를 보라).

간단한 예제

이 예제는 Person을 정의하며 first_name 과 last_name을 가지고 있다.:

from django.db import models

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

first_name과 last_name은 모델의 필드들이다. 각각의 필드는 클래스의 속성으로 정의되어 있으며, 각각의 속성은 데이터베이스 컬럼에 매핑된다. 

위의 Person 모델은 아래와 같은 테이블을 생성할 것이다:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

몇가지 기술적인 사항:

  • 테이블의 명칭인 myapp_person자동으로 생성되는 이름(app명칭 + '_' + 소문자모델클래스명)이다. 보다 자세한 사항은 테이블 명칭을 보라.
  • primary key의 역할을 하는 한 개의 id 필드가 자동으로 추가되지만 다른 필드에 primary key 속성을 주면 오버라이딩 된다. 자동으로 추가되는 primary key 필드를 보라.
  • 이 예의 CREATE TABLE SQL 문장은 PostgreSQL의 SQL 문장이나 , Django는 설정 파일에 정의되어 있는 백엔드 데이터베이스에 적합하게 바뀐 SQL을 사용하므로 걱정할 필요는 없다. 

모델 사용

모델을 정의하고 나면 Django가 그 모델들을 사용할 수 있도록 말해줄 필요가 있다. 셋팅 파일의 INSTALLED_APPS설정에 models.py를 포함하고 있는 모듈의 명칭을 넣어 주면 된다. 

예를 들어, 모델이  myapp.models (manage.py startapp 스크립트로 생성된 어플리케이션의 패키지 구조) 모듈에 있다면, INSTALLED_APPS 에 아래와 같이 추가주어야 한다: 

INSTALLED_APPS = [ #... 'myapp', #... ] 

INSTALLED_APPS에 새로운 앱을 추가하고 나면, 반드시 manage.py migrate를 실행하고, 경우(모델이 변경된 경우?)에 따라서는 manage.py makemigrations명령을 먼저 실행하여 마이그레이션을 생성하라.  

필드들

모델의 가장 중요한 부분은 모델이 정의하는 데이터베이스의 목록이다. 필드는 클래스의 속성으로 정의한다. cleansave, 또는 delete와 같은 models API와 충돌하는 필드명은 사용하지 못한다:

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 클래스의 인스턴스여야만 한다. Django 는 필드 클래스 형을 다음과 같은 것을 결정하는데 사용한다:

  • 컬럼 형, 이 것은 데이터베이스에게 어떤 종류의 데이터 (예를 들면, INTEGERVARCHARTEXT)가 저장될 것인지를 알려준다. 
  • 폼 필드를 랜더링할 때 사용할 디폴트 HTML widget  (예를 들어, <input type="text"><select>).
  • Django admin이나 자동으로 생성된 폼에서 사용되는 최소한의 유효성 검증 요구사항

Django는 수십개의 내장된 필드 형을 가지고 있으며, 전체 필드 형의 목록은 모델 필드 참조문서에 있다. 만일 내장된 함수가 지원하지 않는 것이 있으면 직접 만들면 된다. 커스텀 모델 필드 작성하기를 보라. 

필드 Option

각 필드는 필드에만 적용되는 인자의 셑을 가진다(상세한 내용은 모델 필드 참조 문서에 기술되어 있음) 예를 들어, CharField 는(그리고 그 것의 서브클래스들은) max_length라는 인자를 필요로 하는데 이 것은 데이터를 저장할 VARCHAR 데이터베이스 필드의 크기를 정의한다. 

모든 필드에 공통으로 정의되는 인자들이 있는데 모두가 optional 인자들이다. 그 것들은 참조문서에 충분히 설명이 되어 있으며 다음은 가장 많이 사용하는 것들에 대한 간단한 설명이다:

null
만일 참(True)이면 Django 는 값이 빈 경우 NULL로 데이터베이스에 저장할 것이다. 기본 값은 False이다. 
blank

만일 참(True)이면 그 필드는 공백이 허용된다. 기본 값은 False이다. 

이 것은 null과는 다르다는 것에 주의하라. null 은 순전히 데이터베이스와 관련된 것이고 blank는 유효성 검증과 관련이 있는 것이다. is purely database-related, whereas blank is validation-related. 만일 어떤 필드가 blank=True이면 폼의 유효성 검증은 공백이 들어가는 것을 허용할 것이다. 만일 필드가 blank=False이면 그 필드는 공백을 허용하지 않는다.

choices

이 필드에 대한 선택으로 사용되는 Iterable(멤버를 하나씩 반환 가능한, 예를 들어 tuple의 리스트)을 지정한다. 이렇게 값이 주어지면, 기본 폼 위젯은 텍스트 필드가 아닌 select box이며 정의된 것들 중에 선택하도록 제한될 것이다.

선택 목록은 아래와 같음:

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

각 tuple의 첫 번째 요소는 데이터베이스에 저장되는 값이 될 것이다. 두 번째 요소는 기본 폼 위젯 또는 ModelChoiceField. 에 보여지게 될 것이다. 모델의 인스턴스가 생성되면, 선택 필드에 보여지는 값은 get_FOO_display() 메서드로 접근이 가능하다. 예를 들어 get_shirt_size_display() 처럼...:

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'
default
필드의 기본 값. 이 것은 값 또는 호출가능한 객체가 될 수 있다. 만일 호출가능한 객체라면 새로운 클래스 객체가 생성될 때마다 호출될 것이다.
help_text
폼 위젯에 보여질 추가적인 "도움말" 텍스트. 필드를 폼에서 사용하지 않는 경우라 하더라도 문서화를 위해 유용하다.
primary_key

만일 True이면, 이 필드는 모델의 primary key이다. 

만일 특별히 모델의 어떤 필드를 primary_key=True 를 지정하지 않으면, Django는 자동적으로 IntegerField 를 생성하여 primary key로 삼는다. 그러므로 특정 필드를 primary key로 삼고 싶은 경우를 제외하고는 굳이 primary_key=True를 지정할 필요 없다.  더욱 자세한 정보는 자동으로 생성되는 primary key 필드를 보라

primary key 필드는 읽기 전용이다(당연한거 아냐? ^^). 만일 기 존재하는 객체의 primary key의 값을 변경하고 저장하려고 하면, 기존 것과 별도로 새로운 객체가 만들어질 것이다. 예를 들면:

from django.db import models

class Fruit(models.Model):
    name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
['Apple', 'Pear']
unique
만일 True이면, 이 필드는 전체 테이블에서 unique해야 한다.


자동으로 생성되는 primary key 필드

기본적으로, Django는 각각의 모델에 아래의 필드를 제공한다.:

id = models.AutoField(primary_key=True) 

이 것은 자동으로 증가하는 primary key 이다.

커스텀 primary key를 설정하고 싶으면 모델의 필드 중 하나에 primary_key=True라고 지정하면 된다. Django가 명시적으로 표현된 것을 모게 되면 자동으로 생성되는 id 컬럼을 추가하지 않는다.

각 각의 모델을 명시적이든 아니든 정확히 하나의 필드 만 primary_key=True 설정을 가질 수 있다. 그러면 복합 primary key는 어떻게 하지?

Verbose field names(사람이 읽기 편한 필드명)

ForeignKeyManyToManyField 그리고 OneToOneField를 제외한 각각의 필드는 첫 번째 인자(optional)로 verbose name을 갖는다. verbos name이 지정되지 않으면 Django는 자동으로 필드 속성 명을 가지고 '_"을 공백으로 변환하여 생성한다.

아래 예제에서는 verbose name은 "person's first name"이다:

first_name = models.CharField("person's first name", max_length=30)

아래 예제에서는 verbose name은 "first name"이다:

first_name = models.CharField(max_length=30)

ForeignKeyManyToManyField 그리고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",
)

verbose_name의 첫 자는 소문자로하는 것이 관례이다. 첫 문자가 대문자라야 하는 경우가 생기면 Django가 자동으로 그렇게 한다.

관계

RDB의 장점이 테이블 각각의 상호 관계를 맺는 것이라는 것은 명백하다. Django는 가장 공통적인 3가지의 데이터베이스 관계를 정의하는 기능을 제공한다: 다-대-일, 다-대-다, 일-대-일.

다-대-일 관계

다-대-일 관계를 정의하려면, django.db.models.ForeignKey를 사용하라. 여러분은 여타의 필드 형처럼 모델클래스의 속성으로 포함시키는 방식을 사용한다.

ForeignKey 는 모델과 관련된 클래스 같은 위치매개변수(positional argument)가 필요하다.

예를 들면, 한 개의 Car 모델은 한 개의 Manufacturer 를 가진다면 - 즉, 하나의 Manufacturer는 여러 개의 Car를 생산하지만 각 Car는 오직 한 개의 Manufacturer만 있다면 - 아래의 정의를 사용하라:

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    # ...

재귀 관계(자기 자신에 대해 다-대-일 관계를 가진 객체) 와 아직 정의하지 않은 모델과의 관계도 생성할 수 있다; 보다 자세한 것은 모델 필드 참조문서를 보라.

ForeignKey 필드(예제의 manufacturer)의 이름은 소문자 모델의 명이어야 한다고 권고하고는 있지만 필수는 아니다. 예를 들면:

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(
        Manufacturer,
        on_delete=models.CASCADE,
    )
    # ...

참고

ForeignKey 필드는 많은 수의 추가 인자들을 수용하는데 이는 모델 필드 참조문서에 설명되어 있다. 이러한 인자(Optional)는 관계가 어떻게 작동해야 하는 지 정의하는 역할을 하는데 모두가 선택적 인자이다.

For details on accessing backwards-related objects, see the Following relationships backward example.

샘플 코드는 Many-to-one rel다-대-일 모델 예제를 보라

다-대-다 관계

다-대-다 관계를 정의하려면, ManyToManyField를 사용하라. 여러분은 여타의 필드 형처럼 모델의 클래스 속성으로서 포함시키는 방식으로 사용할 수 있다.

ManyToManyField는 위치매개변수(positional argument)가 필요하다: 모델과 관련이 있는 클래스 

예를 들어, 만일 한 개의 Pizza가 여러개의 Topping 객체를 가진다면 - 즉, 한 개의 Topping은 다 수의 Pizza에 올려질 수 있고, 각 각의 Pizza는 다수의 Topping을 올릴 수 있다면 - 아래에 어떻게 표현하는지 나와 있다:

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping) 

ForeignKey를 가지고 재귀 관계(자기 자신에 대해 다-대-다 관계를 가진 객체) 와 아직 정의하지 않은 모델과의 관계; 도 생성할 수 있다.

ManyToManyField(위의 예제에서 toppings)의 이름이 관련된 모델 객체를 묘사하는 복수로 표현되어야 하는 지는 필수는 아니지만 권고되고 있다. 

어떤 모델이 ManyToManyField를 가지는지는 중요하지 않으나, 반드시 둘 중 하나의 모델에만 정의해야 한다.

일반적으로, ManyToManyField 인스턴스는 폼에서 편집되어야 하는 객체에 있어야 한다. 위의 예제에서 보면, Topping이  한 개의 pizzas ManyToManyField를 가지고 있는 것이 toppings이 Pizza 안에 있는데, 토핑이 피자 여러개 위에 있는 것 보다는 피자에 토핑이 여러개 있다고 생각하는 것이 좀 더 자연스럽기 때문이다. 위와 같이 설정하여야, Pizza 폼에서 사용자들이 토핑을 선택할 수 있게 될 것이다.

See also

예제 소스 전체를 보려면 Many-to-many 다-대-다 관계 모델 예제를 보라.

ManyToManyField 필드는 또한 추가적인 많은 수의 인자를 받는데, 자세한 것은 모델 필드 참조문서에 설명되어 있다. 이러한 옵션들은 관계가 어떻게 작동해야 하는 지를 정의하는데 다 optional이다.

다-대-다 관계에서의 부가적인 필드(Optional)

피자와 토핑을 섞고 매치시키는 단순한 다-대-다 관계를 다루기만 한다면 표준의 가 필요한 전부이다. 그러나, 두 모델 간의 관계를 가지고 데이터를 연관을 지으려고 할 때가 있다. 

예를 들어, 어떤 음악가가 소속된 뮤지컬 그룹을 추적하는 애플리케이션의 경우를 고려해보라. 한 명의 사람과 그 들이 멤버인 그룹과의 다-대-다 관계가 있으면 ManyToManyField를 사용해서 관계를 표현할 수 있다. 그러나, 당신이 수집하고자 하는 멤버쉽에 관해 많은 수의 세부 내역이 있을 수 있다. 예를 들면, 그 사람이 그룹에 참여한 날짜 같은 것.

이러한 상황에 대해, Django는 다-대-다 관계를 지배하는(?)데 사용할 수 있는 모델을 지정할 수 있게 한다. 그리고 나서 그 중개 모델에 별도의 필드들을 추가할 수 있다. 그 중개 모델은 중개자 역할을 할 모델을 가리키는 through인자를 사용하여 ManyToManyField와 연관을 맺는다. 음악가 샘플에서, 코드는 다음과 같을 것임:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):              # __unicode__ on Python 2
        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)

모델을 설정할때, 명시적으로 다-대-다 관계에 관련된 모델들에 foreign key키를 지정한다. 이렇게 명시적으로 선언함으로서 두 모델의 관계를 정의하게 된다. 

중개 모델에는 몇가지 제약사항이 있다:

  • 중개모델은 소스 모델에 대한 오로지 한 개의 foreign key(이 예제에서는 Group)를 포함하거나, 명시적으로 Django가  ManyToManyField.through_fields를 사용하는 관계를 위해 사용할 foreign key를 명적으로 지정하거나 해야만 한다.(둘 중 하나는 해야 한다.) 만일 한 개 이상의 foreign key를 가지고 있고 through_fields가 지정되지 않았다면, 유효성 검증 오류가 발생할 것이다. 유사한 제약사항이 타겟 모델의 foreign key(여기에서는 Person)에도 적용된다.
  • 중개모델을 통해 자기 자신과 다-대-다 관계를 가진 모델은 동일한 모델에 대한 두개의 foreign key를 허용한다. 그러나, 그 것들은 다-대-다 관계의 두개의 다른 측면으로 취급되어질 것이다(?). 비록 두개 이상의 외래 키가 존재하지만 위의 예처럼 through_fields를 지정하지 않으면 유효성 검증 에러가 발생할 것이다.
  • 중개 모델을 이용하여 자기 자신에 대해 다-대-다 관계를 정의할 때는, 반드시 symmetrical=False(모델 필드 참조문서를 보라)를 이용하여야 한다.

이제 여러분은 중개 모델을 사용하여 ManyToManyField(여기에서는 Membership)를 설정하였기 때문에, 다-대-다 관계를 생성할 준비가 된 것이다. 중개 모델의 인스턴스를 생성하면 된다.:

>>> 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>]>

일반적인 다-대-다 필드와 달리, add()create() 또는 set()를 관계를 생성하는데 사용할 수 없다:

>>> # 아래 문구는 작동하지 않는다. >>> beatles.members.add(john) >>> beatles.members.create(name="George Harrison") >>> beatles.members.set([john, paul, ringo, george])

왜? 쉽게 한 개의 Person과 한 개의 Group간의 관계를 생성할 수는 없다 - Membership모델이 요구하는 관계를 위한 모든 상세 내역을 지정할 필요가 있다. addcreate 그리고 할당 호출만 가지고는 이러한 추가적인 상세 내역을 제공할 방법이 없다. 결과적으로 그 것들은 중개 모델을 사용하는 다-대-다 관계를 위해 가능하지 않게 되었다. 이러한 형태의 관계를 생성하는 유일한 방법은 중개 모델의 인스턴스를 생성하는 것이다.

remove() 메서드도 유사한 이유로 사용이 가능하지 않다. 예를 들어, 중개 모델에 의해 정의된 custom through table(?)은  (model1, model2) 쌍에 대해 유일함을 강제하지는 않는다, remove()를 호출은 어떤 중개 모델의 인스턴스가 삭제되어야 만 하는지 충분한 정보를 제공할 수 없을 것이다.:

>>> Membership.objects.create(person=ringo, group=beatles, ... date_joined=date(1968, 9, 4), ... invite_reason="You've been gone for a month and we miss you.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]> >>> # 이 코드는 작동하지 않을 것이다. 왜냐하면 어떤 멤버쉽이 제거 되어야 하는지 알 수 없기 때문에 >>> beatles.members.remove(ringo)

그러나, 메서드는 하나의 인스턴스에 대한 모든 다-대-다 관계를 제거하는데 사용할 수 있다:

>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>

중개 모델의 인스턴스를 생성하여 다-대-다 관계를 일단 확립하고 나면, 쿼리를 수행할 수 있다. 일반적인 다-대-다 관계에서와 같이, 다-대-다 관계를 가진 모델의 속성을 이용하여 쿼리를 할 수 있다:

# 이름잉 'Paul'로 시작하는 멤버가 속한 모든 그룹을 찾는 쿼리 >>> Group.objects.filter(members__name__startswith='Paul') <QuerySet [<Group: The Beatles>]>

중개 모델을 사용하기 때문에 또한 그 것의 속성에 대한 쿼리도 가능하다:

# 1961년 1월 이후에 참여한 비틀즈의 전 멤버를 찾는 쿼리 >>> Person.objects.filter( ... group__name='The Beatles', ... membership__date_joined__gt=date(1961,1,1)) <QuerySet [<Person: Ringo Starr]>

멤버쉽 정보에 대한 접근이 필요하다면 직접 Membership모델을 쿼리할 수도 있다:

>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'

같은 정보에 접근하는 다른 방법은 Person객체로부터 다-대-다 역관계(?)을 쿼리하는 것이다:

>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'

일-대-일 관계

일-대-일 관계를 정의하려면 OneToOneField를 사용하라. 다른 Field형을 사용할 때 처럼 모델의 클래스 속성으로 포함하면 된다.

다른 객체를 어떤 방법으로 확장하는 객체의 primary key에 가장 유용하다.(?)

OneToOneField는 모델과 관련된 클래스를 나타내는 위치매개변수(positional argument)가 필요하다. 

예를 들어. "장소"에 관련된 데이터베이스를 만들고 있다면, 주소, 전화번호 등 꽤나 표준적인 것들을 데이터베이스 안에 만들어야 할 것이다. 그리고나서, 그 장소들 위에 Restaurant 데이터베이스를 장소 데이터베이스 만들 때 했던 것을 반복하거나 복제하지 않고 만들고 싶어지면, 모델을 만들 때, 여러분은 Place에 OneToOneField를 가진 Restaurant을 만들 수 있을 것이다(왜냐하면 한 개의 restaurant는 사실상 한 개의 place이며, 이 것을 다루기 위해서는 일반적으로 상속을 사용하며 그 안에는 암시적으로 일-대-일 관계를 포함하고 있다).

ForeignKey에서 처럼 한 개의 재귀 관계 이 정의될 수 있고 아직 정의되지 않은 모델에 대한 참조이 만들어 질 수 있다.

See also

전체 예제는 일-대-일 모델 예제를 보라.

OneToOneField필드는 또한 옵션 인자인 parent_link를 받을 수 있다.

OneToOneField 클래스들은 자동적으로 모델의 primary key가 되고는 했었다. 하지만 이제는 더이상 진실이 아니다(비록 원하면 여러분이 primary_key를 전달할 수는 있을지라도?). 그리하여, 하나의 단일 모델이 복수의 OneToOneField형을 가지는 것이 가능하다.

파일 간의 모델 공유(?)

하나의 앱에서 다른 앱으로 모델을 공유하는 것은 매우 쉽다. 이렇게 하려면, 모델이 정의된 파일의 제일 상단에 관련시키고 싶은 모델을 import하라.  예를 들어:

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,
    )

필드명에 대한 제약사항

Django는 모델 필드명에 대해 단지 두가지의 제약사항이 있다:

  1. Python 예약서를 사용할 수 없다. Python 구문 에러를 유발하기 때문이다. 예를 들어:

    class Example(models.Model):
        pass = models.IntegerField() # 'pass' 예약어거든!
    
  2. 필드명에는 연속으로 두개 이상의 밑줄(_)을 사용할 수 없다. Django가 쿼리를 탐색하는 구문이 작동하는 방식 때문이다. 예를 들어:

    class Example(models.Model):
        foo__bar = models.IntegerField() # 'foo__bar' 는 밑줄이 두개군요!
    

그러나, 이러한 제약사항들은 그럭저럭 문제 없이 개발할만 하다. 필드명이 반드시 데이터베이스 컬럼 명과 일치할 필요는 없기 때문이다.  db_column옵션을 보라.

joinwhere 또는 select 같은 SQL 예약어도 모델 필드명으로 허용되는데, Django SQL  쿼리문에 있는 모든 데이터베이스 테이블명과 컬럼명을 이스케이프(escape문자처럼 원래 문자와 다른 것으로...)하기 때문이다. 여러분이 사용하는 데이터베이스 엔진에 특화된 인용문을 사용한다.

커스텀 필드형

여러분이 달성하고자 하는 목적에 기존의 모델 필드가 적합하지 않으면, 또는 어떤 덜 공통적인 데이터베이스 컬럼의 이점을 취하고자 하면, 자신만의 필드 클래스를 만들 수있다. 자신만의 필드를 생성하는 것과 관련된 전체 내용은 커스텀 모델 필드 작성하에 제공되어 있다.

Meta 옵션

모델 내부에 class Meta를 사용하여 모델에 메타데이터를 줄 수 있다.:

from django.db import models

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

모델 메타데이터는 "주문 선택사항 (ordering), 데이터베이스 테이블명(db_table) 또는 가독성있는 단수 및 복수 명(verbose_name 와 verbose_name_plural) 같은필드가 아닌 어떤 것이다. 어떤 것도 필수는 아니며, class Meta를 추가하는 것도 완전히 선택적이다.

모든 가능한 Meta옵션은 모델 옵션 참조문서에서 찾을 수 있다.

모델의 속성들

objects
모델의 가장 중요한 속성은 Manager이다. 어떤 데이터베이스 쿼리 작업이 Django에게 제공되는 인터페이스이며 인스턴스를 찾아오는데 사용된다. 만일 커스텀 Manager가 정의되지 않으면, 기본 이름이 objects이다. Manager는 모델 인스턴스가 아니라 모델 클래스를 통해서만 접근이 가능하다.

모델 메서드들

당신의 객체에 커스텀 "row-level" 기능을 추가하려면 커스텀 메서드를 정의하라. Manager메서드가 테이블 수준의 것을 의도하는 반면에, 모델 메서드는 특정한 모델 인스턴스(요것이 row-level이겠지 ^^)에 작용해야하만 한다.

모델에 비즈니스 로직을 유지하는 것은 가치있는 테크닉이다. 예를 들어, 아래는 몇 개의 커스텀 메서드를 가지고 있다:

from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) birth_date = models.DateField() def baby_boomer_status(self): "개인의 베이비부머 상태를 반환." import datetime if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" elif self.birth_date < datetime.date(1965, 1, 1): return "Baby boomer" else: return "Post-boomer" def _get_full_name(self): "사람의 전체 이름을 반환." return '%s %s' % (self.first_name, self.last_name) full_name = property(_get_full_name)

이 예제의 마지막 메서드는 property 이다.

모델 인스턴스 참조문서각 모델에 자동적으로 생성되는 메서드들의 완벽한 리스트를 제공한다.이 들 대부분을 오버라이드할 수 있다 - 사전 정의된 모델 메서트의 오버라이딩 문서를 보라. 그러나 항상 재정의하고 싶어지는 것들이 몇 개 있다. 아래를 보라:

__str__() (Python 3)

Python이 "마법같은 메서드"로 어떤 객체든지 unicode "표현(?)"으로 반환한다. 이 것은 평범한 문자열로써 보여지거나 강제될(coerced) 필요가 있을 때면 언제나 Django와 Python이 사용하는 것이다. 가장 뚜렷한 경우는 인터렉티브 콘솔이나 관리 기능에서 객체를 보여줄 때 발생한다.

여러분은 언제나 이 메서드를 정의하기를 원할 것이다: 기본 메서드는 그다시 도움이 되질 않는다.

__unicode__() (Python 2)
__str__()에 해당하는 Python 2 메서드
get_absolute_url()

이 메서드는 Django에게 객체에 대한 URL을 어떻게 계산해야 하는지를 알려준다. Django는 관리자 인터페이스나, 객체에 대한 URL을 알아낼 필요가 있을 때면 언제나 이 메서드를 사용한다.

객체를 유일하게 식별하는 URL을 가진 객체는 이 메서드를 정의해야만 한다.

사전에 정의된 모델 메서드들을 오버라이딩하기

여러분이 커스터마이즈하기를 원할 데이터베이스를 조작하는 행위를 감싸고 있는 또 다른 모델 메서드들이 있다. 특히, 여러분은 save()와 delete()가 작동하는 방식을 바꾸기를 종종 원하게 될 것이다.

맘대로 이 메서드들을(다른 것들도) 오버라이드하여 작동방식을 변경해도 좋습니다.

전통적인 내장 메서드의 오버라이드의 유스케이스는 객체를 저장할 때마다 뭔가 일어나기를 바라는 경우였다. 예를 들어(save()가 어떤 파라미터를 받을 수 있는 지 무서를 보라):

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()

또는 저장을 방해할 수도 있다:

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        if self.name == "Yoko Ono's blog":
            return # Yoko shall never have her own blog!
        else:
            super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.

그 객체가 여전히 데이터베이스에 저장되어야 한다면 수퍼클래스의 메서드-super(Blog, self).save(*args, **kwargs)-를 호출하는 것을 기억하는 것이 중요하다. 만일 수퍼클래스의 메서드를 호출하는 것을 잊는다면, 기본으로 정의된 행동을 일어나지 않을 것이고 데이터베이스는 건드려지지도 않을 것이다.

또한 모델 메서드에 전달될 수 있는 인자들*args, **kwargs -을 모두 전달해야 하는 것도 중요하다. Django는 때때로 내장 모델 메서드의 기능을 확장하면서 새로운 인자를 추가하기도 할 것이다. 만일 여러분이 메서드를 정의할 때 *args,**kwargs 인자를 쓴다면, 여러분이 작성한 코드가 자동적으로 그 들이 추가한 인자들까지 지원할 것을 보장 받을 수 있다.(어쨋든 수퍼클래스의 메서드를 호출하고, 인자도 

대량작업을 수행할 때는 오버라이드된 모델 메서드는 호출되지 않은다

QuerySet을 이용하거나 cascading delete의 결과로 대량으로 객체를 삭제할 때는 객체의 delete() 메서드는 반드시 호출된다고 볼 수는 없다는 점에 주의하라. 커스터마이즈한 삭제 로직이 반드시 수행되기를 바란다면  pre_delete와/또는 post_delete 시그널(이벤트?)를 사용하라.

불행하게도 객체를 대향으로 생성하거나 갱신할 때는 위와 같은 제2의 해결책은 없다. 왜야하면, save(),  pre_save그리고 post_save 중 어느 것도 호출되지 않기 때문이다.

커스텀 SQL 실행

또 다른 공통적인 패턴(overriding)은 모델 메서드와 모듈 수준의 메서드 안에서 커스텀 SQL 문장을 작성하는 것이다. SQL을 그래도 사용하는 방법에 대한 자세한 사항은 SQL 생짜로 사용하기에 관한 문서를 보라.

모델 상속

Django의 모델 상속은 Python의 일반적인 모델 클래스 상속의 방식과 거의 동일하게 작동하지만 이 문서의 처음에 설명한 기본은 여전히 따라야 한다. 즉 베이스 클래스는 반드시 django.db.models.Model의 서브클래스라야 한다. 

The only decision you have to make is whether you want the parent models to be models in their own right (with their own database tables), or if the parents are just holders of common information that will only be visible through the child models.

Django에서 가능한 세가지 스타일의 상속이 있다.

  1. 종종 여러분은 각 각의 자식 클래스에서 따로 타이핑 하기를 원치 않는 정보를 보유한 부모 클래스를 원할 때가 있을 것이다. 이 클래스는 단독으로는 사용되지 않을 것이므로 Abstract base classes가 여러분이 추구하는 것이다.
  2. 만일 여러분이 현존하는 모델(아마도 다른 어플리케이션으로 부터 온전히 만들어진)로 부터 상속을 받으려고 하고 각 각의 모델이 각자 자기 자신의 데이터베이스 테이블을 가지기를 원한다면, Multi-table inheritance가 여러분이 가야할 길이다.
  3. 마지막으로, 모델의 필드를 변환시키지 않고 Python 수준의 행위만 수정하기를 원한다면, Proxy models를 사용할 수 있다.

Abstract base classes

추상 베이스 클래스는 여러분이 어떤 공통의 정보를 다른 다수의 모델에 넣기를 원할 때 유용하다. 베이스 클래스를 하나 만들고 Meta클래스에 abstract=True라고 적어 놓으면 된다. 이 모델은 어떤 데이터베이스 테이블을 생성하는데는 사용할 수 없다. 대신에, 이 것이 다른 모델의 베이스 클래스가 되면, 이 베이스 클래스가 가진 필드들이 그 자식 클래스에 추가될 것이다. 추상 베이스 클래스에 있는 것돠 동일한 이름을 가진 필드를 자식 클래스에 추가하는 것은 오류가 발생한다.(그렇게 하면 Django가 예외를 일으킬 것이다.)

예:

from django.db import models

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

Student 모델은 세 개의 필드를 가질 것이다: nameage 그리고 home_group. The CommonInfo 모델은 추상 베이스 클래스이므로 보통의 Django 모델로 사용될 수 없다. 이 것은 데이터베이스 테이블을 생성하거나 매니저를 가질 수도 없고 인스턴스를 생성하거나 직접적으로 저장될 수도 없다.

괘 많은 경우에 이러한 형태의 모델 상속은 정확히 여러분이 원하는 것일 것이다. 이 것은 데이터베이스 수준에서는 각 자식 클래스 당 한 개의 테이터베이스 테이블을 생성하면서도 Python 수준에서 공통의 요소를 추출하는 방법을 제공한다. 

Meta 클래스 상속

추상 베이스 클래스를 생성할 때, Django는  베이스 클래스의 속성으로 선언된 Meta 내부 클래스를 만든다. 자식 클래스가 자신만의 클래스를 선언하지 않으면, 부모의 Meta를 상속받을 것이다. 만일 자식 클래스가 부모의 Meta클래스를 확장하고자 한다면 부모의 Meta클래스를 상속받으면 된다. 예를 들면:  

from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

Django는 추상 베이스 클래스의 Meta클래스에 한 가지 조정을 가한다: 속성을 설치하기 전에, abstract=False를 설정한다. 이 것은 추상 베이스 클래스의 자식 클래스는 자동적으로 추상클래스화하지 않는다는 뜻이다. 물론 다른 추상 베이스 클래스로부터 상속된 추상 베이스 클래스를 만들 수 없는 것은 아니다. 단지 명시적으로 매 번 abstract=True를 설정하는 것을 기억하면 된다.

몇 몇 속성들은 추상 베이스 클래스의 Meta클래스에 포함하는 것이 바람직하지 않을 것이다. 예를 들어, 속성을 포함하게 되면 모든 자식 클래스들이(자기 자신의 Meta클래스에 속성을 지정하지 않은) 동일한 데이터베이스 테이블을 사용하게 될 것인데, 분명히 이 같은 상호아을 여러분이 원하지 않을 것이다.

다중 테이블 상속

Django가 지원하는 두 번째 형태의 모델 상속은 계층 구조 내에 있는 모델이 그 자체 일 때이다(?). 각 각의 모델은 그 자신의 데이터베이스 테이블에 대응되며 개별적으로 생성되고 쿼리를 수행할 수 있다. 상속 관계는 자식 모델과 각 각의 부모 간(자동으로 생성된 OneToOneField를 통해)의 링크를 소개(?)한다.

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

Place의 모든 필드는 Restaurant에도 또한 유요하다 비록 그 데이터는 다른 데이터베이스 테이블에 존재하더라도. 그래서 이런 것들이 둘 다 가능하다:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

I만일 Restaurant이면서 Place인 것을 가지고 있다면, 여러분은 소문자로 된 모델 명을 가지고 Place객체로부터 Restaurant객체를 가져올 수 있다:

>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>

그러나, 만일 위의 예제의 p가 Restaurant(객체로부터 직접적으로 생성되었었다거나 다른 클래스의 부모였거나)이 아니라면, p.restaurant을 언급하면 Restaurant.DoesNotExist예외가 발생할 것이다.

메타 그리고 다중 테이블 상속

다중테이블 상속 상황에서는, 자식클래스가 부모클래스의 Meta클래스로부터 상속받는 것은 말이 안된다. 모든 Meta옵션들이 이미 부모 클래스에 적용되어 있는데 그 것들을 다시 자식 클래스에 적용하게 되면 일반적으로는 모순된 행동을 하게 만들 것이다(추상 베이스 클래스의 경우와는 상반되기는 하는데, 베이스 클래스에는 본질적으로 존재하지 않기 때문이다).

그래서 자식 모델은 그 부모의 Meta클래스에 접근하지 못한다. 그러나, 부모로부터 자식클래스가 상속받을 수 있는 몇 개의 제한적인 행동이 있다: 만일 자식 클래스가 ordering속성 또는 get_latest_by속성을 지정하지 않았다면, 이러한 속성들은 부모로부터 물려받게 될 것이다.

만일 부모클래스에는 ordering이 있고 여러분이 자식클래스가 natural ordering을 갖기를 원하지 않는다면, 명시적으로 기능을 억제하라:

class ChildModel(ParentModel): # ... class Meta: # 부모클래스의 ordering 효과를 제거 ordering = []

상속 과 역 관계(?)

다중테이블 상속은 암시적인 OneToOneField를 사용하여 자식과 부모를 연결하기 때문에, 저 위의 예처럼 부모로부터 자식으로 이동하는(?) 것이 가능하다. 그러나, 이 것은 ForeignKey와 ManyToManyField관계를 위한 기본 related_name값을 이용한다. 만일 여러분이 부모 모델의 서브클래스에 그러한 형태의 관계를 맺는다면, 각 각의 그런 필드에 대해 related_name속성을 지정해야만 한다. 그렇게 하는 것을 잊으면, Django는 유효성 검증 오류를 발생시킬 것이다.

예를 들어, 위에서 예로 든 Place클래스를 가지고 한 개의 ManyToManyField를 가진 다른 서브클래스를 생성해보자:

class Supplier(Place):
    customers = models.ManyToManyField(Place)

이러면 아래와 같은 에러가 발생된다:

Reverse query name for 'Supplier.customers' clashes with reverse query
name for 'Supplier.place_ptr'.

HINT: Add or change a related_name argument to the definition for
'Supplier.customers' or 'Supplier.place_ptr'.

다음처럼 customers필드에 을 related_name추가하면 이 에러가 해결될 것이다: models.ManyToManyField(Place,related_name='provider').

대리자(Proxy) 모델

multi-table inheritance를 이용하면, 한 개의 새로운 데이터베이스 테이블이 각 각의 서브클래스 모델마다 생성된다. 이 것은 일반적으로 벌어지기를 바라는 행동인데, 왜냐하면 서브클래스도 베이스 클래스에 존재하지 않은 추가적인 데이터 필드를 저장할 장소가 필요하기 때문이다. 그러나, 때때로 여러분은 단지 모델에 대해 Python 차원에서만 변화- 아마도, 기본 매니저를 변경하거나 새로운 메서드를 추가하는 -를 원할 것이다. 

이 것이 원래의 모델에 대한 대리자를 생성하는 대리자 모델 상속이 필요한 이유이다. 여러분은 마치 여러분이 원래의(대리자가 아닌) 모델을 사용하고 있는 것처럼 대리자 모델의 인스턴스를 생성, 삭제, 갱신할 수 있고 모든 데이터를 저장할 수 있다. 차이는 대리자의 기본 모델 ordering 또는 기본 매니저 같은 것들을 원본을 변경하지 않고 변경할 수 있다는 것이다.

대리자 모델도 보통의 모델과 같은 방식으로 선언한다. Meta클래스의 proxy속성을 True로 설정하면 된다.

예를 들어, Person모델에 메서드를 추가하기를 원한다면, 다음과 같이 할 수 있다:

from django.db import models

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

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

MyPerson클래스는 그 것의 부모인 Person클래스와 동일한 데이터베이스 테이블을 가지고 작동한다. 특히, Person클래스의 어떤 새로운 인스턴스도 MyPerson을 통해 접근이 가능하며, 그 반대도 마찬가지다I:

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

You could also use a proxy model to define a different default ordering on a model. 대리자 모델은 하나의 모델에 기본 ordering을 달리하는 곳에도 사용할 수 있다. 여러분은 Person모델을 항상 정렬하기를 원하는 것은 아니지만, 주기적으로 last_name 속성에 의해 정렬되기를 원하면 대리자를 사용하면 된다. 어렵지 않다:

class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True

이제 정상 Person 쿼리는 정렬되지 않고, OrderedPerson쿼리는 last_name에 의해 정렬될 것이다.

대리자 모델도 Meta속성을 정규 모델과 동일한 방식으로 상속한다.

QuerySets still return the model that was requested

There is no way to have Django return, say, a MyPerson object whenever you query for Person objects. A queryset for Person objects will return those types of objects. The whole point of proxy objects is that code relying on the original Person will use those and your own code can use the extensions you included (that no other code is relying on anyway). It is not a way to replace the Person (or any other) model everywhere with something of your own creation.

Base class restrictions

대리자 모델은 정확히 한 개의 비추상 모델 클래스로 부터 상송되어야 한다. You can’t inherit from multiple non-abstract models as the proxy model doesn’t provide any connection between the rows in the different database tables. A proxy model can inherit from any number of abstract model classes, providing they do not define any model fields. A proxy model may also inherit from any number of proxy models that share a common non-abstract parent class.

Changed in Django 1.10:

In earlier versions, a proxy model couldn’t inherit more than one proxy model that shared the same parent class.

Proxy model managers

If you don’t specify any model managers on a proxy model, it inherits the managers from its model parents. If you define a manager on the proxy model, it will become the default, although any managers defined on the parent classes will still be available.

Continuing our example from above, you could change the default manager used when you query the Person model like this:

from django.db import models

class NewManager(models.Manager):
    # ...
    pass

class MyPerson(Person):
    objects = NewManager()

    class Meta:
        proxy = True

If you wanted to add a new manager to the Proxy, without replacing the existing default, you can use the techniques described in the custom manager documentation: create a base class containing the new managers and inherit that after the primary base class:

# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
    secondary = NewManager()

    class Meta:
        abstract = True

class MyPerson(Person, ExtraManagers):
    class Meta:
        proxy = True

You probably won’t need to do this very often, but, when you do, it’s possible.

Differences between proxy inheritance and unmanaged models

Proxy model inheritance might look fairly similar to creating an unmanaged model, using the managed attribute on a model’s Meta class.

With careful setting of Meta.db_table you could create an unmanaged model that shadows an existing model and adds Python methods to it. However, that would be very repetitive and fragile as you need to keep both copies synchronized if you make any changes.

On the other hand, proxy models are intended to behave exactly like the model they are proxying for. They are always in sync with the parent model since they directly inherit its fields and managers.

The general rules are:

  1. If you are mirroring an existing model or database table and don’t want all the original database table columns, use Meta.managed=False. That option is normally useful for modeling database views and tables not under the control of Django.
  2. If you are wanting to change the Python-only behavior of a model, but keep all the same fields as in the original, use Meta.proxy=True. This sets things up so that the proxy model is an exact copy of the storage structure of the original model when data is saved.

다중 상속

Python 서브클래싱과 똑 같이 Django 모델도 다중의 부모 모델로 부터 상속될 수 있다. 보통의 Python 몀칭 충돌방지 룰이 적용됨을 명심하라.  특정한 이름을 가진 (예, Meta) 첫 번째 베이스 클래스가 사용되어질 것이다.(?) 만일 여러개의 부모 가 Meta 클래스라는 동일한 이름의 속성을 가지고 있다면, 제일 첫번 째 부모클래스의 것이 자식에게 적용될 것이고 나머지는 무시될 것이다.

Generally, you won’t need to inherit from multiple parents. The main use-case where this is useful is for “mix-in” classes: adding a particular extra field or method to every class that inherits the mix-in. Try to keep your inheritance hierarchies as simple and straightforward as possible so that you won’t have to struggle to work out where a particular piece of information is coming from.

Note that inheriting from multiple models that have a common id primary key field will raise an error. To properly use multiple inheritance, you can use an explicit AutoField in the base models:

class Article(models.Model):
    article_id = models.AutoField(primary_key=True)
    ...

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    ...

class BookReview(Book, Article):
    pass

Or use a common ancestor to hold the AutoField:

class Piece(models.Model):
    pass

class Article(Piece):
    ...

class Book(Piece):
    ...

class BookReview(Book, Article):
    pass

Field name “hiding” is not permitted

정상적인 Python 클래스 상속에 있어서, 자식 클래스는 부모 클래스의 어떤 속성도 재정의하는 것이 허용된다. Django에서는 모델 필드에 대해서는 일반적으로 그 같은 것이 허용되지 않는다. 비추상 모델 베이스 클래스가 author라는 필드를 가지고 있을 때, 여러분은 그 베이스 클래스를 상속한 어떤 클래스에서도 author라고 불리는 속성을 정의하거나 생성할 수 없다. 

이러한 제약은 추상 모델로부터 상속한 모델 필드에는 적용되지 않는다. 그러한 필드 들은 다른 필드 도는 값으로 재정의 되거나 field_name = None을 설정하여 제거할 수도 있다.

Changed in Django 1.10:

추상 클래스를 재정의하는 기능이 추가되었다.

경고

모델 매니저는 추상 베이스 클래스를 상속하였다. 상속된 Manager에 의해 참조되고 있는 상속된 필드를 재정의하면 사소한 버그를 유발할 수 있다. custom managers and model inheritance를 보라.

주의사항

어떤 필드는 모델상에서 추가 속성을 정의한다, 예를 들어, ForeignKey는 필드명에 _id를 붙인 추가 속성, foreign model의 related_name과 related_query_name을 정의한다.

이 추가 속성들은 그 들을 정의한 필드가 변경 또는 제거되어 더 이상 추가 속성을 정의할 수 없게 되기 전에는 재정의할 수 없다.

부모 모델의 필드를 재정의하게 되면 새로운 인스턴스(Model.__init__에서 어떤 필드가 초기화되어야 하는지를 지정하는 것)를 초기화하거나 시리얼라이즈하는데 어려움이 생긴다. 이러한 것들은 보통의 Python 클래스 상속에서는 동일한 방법으로 다룰 필요가 없는 특징들이다. 그래서 Django 모델 상속과 Python 클래스 상속의 차이는  임의적이지 않다(룰이 있다?). 

이러한 제약은 Field인스턴스인 속성에만 적용된다. 보통의 Python 속성은 원하면 재정의할 수 있다. It also only applies to the name of the attribute as Python sees it: if you are manually specifying the database column name, you can have the same column name appearing in both a child and an ancestor model for multi-table inheritance (they are columns in two different database tables).

Django는 어떤 조상 모델의 어떤 모델 필드를 재정의하면 FieldError를 발생시킬 것이다.

패키지 내의 모델 조직화

manage.py startapp명령은 models.py파일을 포함하는 어플리케이션 구조를 생성한다. 모델의 수가 많다면, 그 것들을 독립된 파일로 만드는 것이 유용할 수 있다.

그렇게 하기 위해서는 models패키지를 생성하라.  models.py를 제거하고 myapp/models/디렉토리를 만들어 __init__.py 파일과 모델을 저장하고 있는 파일 들을 넣어라. 모델들을 __init__.py파일에서 반드시 import해야 한다.

예를 들어, models 디렉토리에 organic.py과 synthetic.py가 있다면:

myapp/models/__init__.py
from .organic import Person
from .synthetic import Robot

from .models import *를 이용하기 보다 명시적으로 각각의 모델을 import하는 것이 네임스페이스를 늘어놓지 않기 위해, 소스코드의 가독성을 높이기에 그리고 코드 분석 도구를 유용하게 하는 데에 장점이 있다.

See also

The Models Reference
모델 필드, 관련 객체 그리고 QuerySet을 포함한 모든 모델관련 API를 담고 있다.