장고에서 일대 다 관계를 표현하는 방법


167

지금 Django 모델을 정의 OneToManyField하고 있으며 모델 필드 유형 이 없다는 것을 깨달았습니다 . 나는 이것을 할 수있는 방법이 있다고 확신하므로 내가 무엇을 놓치고 있는지 잘 모르겠습니다. 나는 본질적으로 다음과 같은 것을 가지고있다 :

class Dude(models.Model):
    numbers = models.OneToManyField('PhoneNumber')

class PhoneNumber(models.Model):
    number = models.CharField()

이 경우 각각에 Dude여러 PhoneNumber개의을 가질 수 있지만 for 와 같은 인스턴스 를 소유하는 많은 다른 객체가있을 수 있으므로 관계 PhoneNumberDude소유 한 대상 을 알 필요가 없기 때문에 관계는 단방향이어야합니다. 예:PhoneNumberBusiness

class Business(models.Model):
    numbers = models.OneToManyField('PhoneNumber')

OneToManyField이런 종류의 관계를 나타 내기 위해 모델에서 무엇을 대체합니까 (존재하지 않음)? 일대 다 관계를 선언하는 것이 가장 쉬운 Hibernate / JPA에서 왔습니다.

@OneToMany
private List<PhoneNumber> phoneNumbers;

장고에서 이것을 어떻게 표현할 수 있습니까?

답변:


133

Django에서 일대 다 관계를 처리하려면을 사용해야 ForeignKey합니다.

ForeignKey에 대한 문서는 매우 포괄적이며 다음과 같은 모든 질문에 답변해야합니다.

https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey

귀하의 예에서 현재 구조를 통해 각 Dude는 하나의 번호를 가질 수 있으며 각 번호는 여러 Dudes (Business와 동일)에 속할 수 있습니다.

반대 관계를 원하면 PhoneNumber 모델에 두 개의 ForeignKey 필드 (하나는 Dude와 하나는 Business)를 추가해야합니다. 이를 통해 각 번호는 하나의 Dude 또는 하나의 비즈니스에 속할 수 있으며 Dudes 및 비즈니스는 여러 개의 번호를 소유 할 수 있습니다. 나는 이것이 당신이 무엇인지 생각합니다.

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)

3
위의 문제가 주어진 예를 들어 주시겠습니까? 아마 그것을 완전히 놓쳤을 지 모르지만, 지금은 Django 문서를 한동안 읽었으며 이런 종류의 관계를 만드는 방법에 대해서는 아직 확실하지 않습니다.
Naftuli Kay

4
외래 키를 필요하지 않게하거나 (blank = True, null = True), 일종의 사용자 지정 유효성 검사를 추가하여 하나 이상이 있는지 확인하십시오. 일반 번호를 가진 비즈니스의 경우는 어떻습니까? 아니면 실직 친구?
j_syk

1
사용자 정의 유효성 검사에 대한 @j_syk 좋은 지적. 그러나 외래 키를 외래 키와 비즈니스에 외래 키를 모두 포함시킨 다음 사용자 정의 (모델 정의 외부) 유효성 검사를 수행하는 것은 일종의 해킹처럼 보입니다. 더 깨끗한 방법이 있어야하는 것처럼 보이지만 알아낼 수는 없습니다.
andy

이 상황에서는 다른 객체와의 일반적인 관계를 허용 하는 ContentTypes Framework 를 사용하는 것이 좋습니다 . 그러나 컨텐츠 유형을 사용하면 매우 빠르게 복잡해질 수 있으며, 이것이 필요한 경우에는 더 간단한 (해키 인 경우) 접근 방식이 바람직 할 수 있습니다.
kball

57
언급해야 할 한 가지는 ForeignKey에 대한 "related_name"인수입니다. 따라서 PhoneNumber 클래스 에는 모든 관련 숫자를 가져 오는 데 dude = models.ForeignKey(Dude, related_name='numbers')사용할 수 있습니다 some_dude_object.numbers.all()( "related_name"을 지정하지 않으면 기본값은 "number_set"임).
markshep

40

장고에서는 일대 다 관계를 ForeignKey라고합니다. 그것은 단지 그렇게보다는 가진, 그러나 한 방향으로 작동 number클래스의 속성을 Dude당신이 필요로하는 것

class Dude(models.Model):
    ...

class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)

많은 모델 ForeignKey이 일대일 모델을 가질 수 있으므로 다음 PhoneNumber과 같은 두 번째 속성을 갖는 것이 유효 합니다.

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)

당신은에 액세스 할 수 있습니다 PhoneNumberA의의를 Dude객체 dd.phonenumber_set.objects.all(), 다음을 위해 유사 할 Business객체입니다.


1
나는 ForeignKey"일대일" 이라는 가정하에있었습니다 . 위의 예를 사용하면 Dude많은 PhoneNumbers권리 가 있어야 합니까?
Naftuli Kay

6
이것을 반영하기 위해 답변을 편집했습니다. 예. ForeignKey를 지정하면 일대일 ForeignKey(Dude, unique=True)이므로 위의 코드를 사용하면 Dude여러 개를 얻을 수 PhoneNumber있습니다.
stillLearning

1
@rolling stone- 감사합니다. 댓글을 달았을 때 실수를 저지른 후에 추가했습니다. Unique = True는 OneToOneField와 똑같이 작동하지 않습니다. Unique = True를 지정하면 ForeignKey가 일대일 관계 만 사용한다고 설명했습니다.
stillLearning

8
에서 +1했습니다 PhoneNumber. 이제 이해하기 시작했습니다. ForeignKey본질적으로 다 대일이므로
일대 다를

2
필드 이름의 중요성을 누군가가 설명 할 수 있습니까 phonenumber_set? 어디에서나 정의되지 않았습니다. "_set"이 붙은 모델명입니까?
James Wierzba


15

OneToMany관계의 많은 측면 (예 : ManyToOne관계) 에서 외래 키를 사용하거나 ManyToMany고유 제약 조건으로 (어느쪽에 서든) 외래 키를 사용할 수 있습니다 .


8

django충분히 똑똑하다. 실제로 우리는 oneToMany필드 를 정의 할 필요가 없습니다 . 자동으로 생성됩니다 django:-). foreignKey관련 테이블 에만 정의하면 됩니다. 즉, ManyToOne를 사용하여 관계 만 정의 하면 foreignKey됩니다.

class Car(models.Model):
    // wheels = models.oneToMany() to get wheels of this car [**it is not required to define**].


class Wheel(models.Model):
    car = models.ForeignKey(Car, on_delete=models.CASCADE)  

특정 자동차의 바퀴 목록을 얻으려면 우리는 python's자동 생성 객체 를 사용할 것 wheel_set입니다. 차 c를 위해 당신은 사용할 것입니다c.wheel_set.all()


5

하지만 롤링 스톤 (Rolling Stone) '의 대답은 간단하고 기능 좋은이다, 나는 그것이 해결되지 않는 두 가지가 있다고 생각합니다.

  1. OP가 전화 번호를 시행하고자한다면 Dude와 Business 모두에 속할 수 없습니다
  2. Dude / Business 모델이 아니라 PhoneNumber 모델에 관계를 정의한 결과 피할 수없는 슬픔의 느낌. 추가 지상파가 지구에 와서 외계인 모델을 추가하려는 경우 단순히 외계인 모델에 "phone_numbers"필드를 추가하는 대신 ET에 전화 번호가 있다고 가정하여 PhoneNumber를 수정해야합니다.

콘텐츠 유형 프레임 워크를 도입하면 PhoneNumber 모델에서 "일반 외래 키"를 작성할 수있는 일부 오브젝트가 노출됩니다. 그런 다음 Dude와 Business의 역 관계를 정의 할 수 있습니다

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models

class PhoneNumber(models.Model):
    number = models.CharField()

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    owner = GenericForeignKey()

class Dude(models.Model):
    numbers = GenericRelation(PhoneNumber)

class Business(models.Model):
    numbers = GenericRelation(PhoneNumber)

자세한 내용은 문서 를 참조 하고 빠른 자습서는 이 기사참조하십시오 .

또한 다음은 Generic FK 사용에 반대 하는 기사 입니다 .


0

"많은"모델이 모델 별 모델 생성을 정당화하지 않는 경우 (여기서는 아니지만 다른 사람들에게 도움이 될 수 있음), 다른 대안은 Django Contrib 패키지 를 통해 특정 PostgreSQL 데이터 유형에 의존하는 것입니다

Postgres는 Array 또는 JSON 데이터 형식을 처리 할 수 있으며, 여러 항목을 하나 의 단일 엔터티에만 연결할 수있는 경우 일대 다를 처리하는 좋은 해결 방법이 될 수 있습니다 .

Postgres를 사용하면 어레이의 단일 요소에 액세스 할 수 있으므로 쿼리가 실제로 빠르며 애플리케이션 수준의 오버 헤드를 피할 수 있습니다. 물론 Django는 이 기능을 활용 하기 위해 멋진 API구현 합니다.

분명히 다른 데이터베이스 백엔드에 이식 할 수 없다는 단점이 있지만 여전히 언급 할 가치가 있습니다.

아이디어를 찾는 사람들에게 도움이되기를 바랍니다.


0

우선 우리는 여행을합니다.

01) 일대 다 관계 :

ASSUME:

class Business(models.Model):
    name = models.CharField(max_length=200)
    .........
    .........
    phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)

class Dude(models.Model):
    name = models.CharField(max_length=200)
    .........
    .........
    phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)

class PhoneNumber(models.Model):
    number = models.CharField(max_length=20)
    ........
    ........

NB : Django는 OneToMany 관계를 제공하지 않습니다. 그래서 장고에서는 위의 방법을 사용할 수 없습니다. 그러나 관계형 모델로 변환해야합니다. 그래서 우리가 뭘 할 수 있지? 이 상황에서 관계형 모델을 역 관계형 모델로 변환해야합니다.

여기:

관계형 모델 = OneToMany

따라서 역 관계형 모델 = ManyToOne

주의 : Django는 ManyToOne 관계를 지원하고 Django에서는 ManyToOne이 ForeignKey로 표시됩니다.

02) 다 대일 관계 :

SOLVE:

class Business(models.Model):
    .........
    .........

class Dude(models.Model):
    .........
    .........

class PhoneNumber(models.Model):
    ........
    ........
    business = models.ForeignKey(Business)
    dude = models.ForeignKey(Dude)

NB : 간단하게 생각하세요 !!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.