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

지금 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;

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



답변

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)


답변

장고에서는 일대 다 관계를 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객체입니다.


답변

더 명확하게 말하면 장고에는 OneToMany가 없으며 ManyToOne 만 있습니다. 이것은 위에서 설명한 Foreignkey입니다. Foreignkey를 사용하여 OneToMany 관계를 설명 할 수 있지만 그 표현은 매우 표현력이 없습니다.

그것에 관한 좋은 기사 :
https://amir.rachum.com/blog/2013/06/15/a-case-for-a-onetomany-relationship-in-django/


답변

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


답변

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


답변

하지만 롤링 스톤 (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 사용에 반대 하는 기사 입니다 .


답변

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

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

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

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

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