2011-08-19 2 views
1

그것은 장고의 공식 문서에서의 : https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationshipsdjango : 다 대 다 관계의 추가 필드에 검은 마법이 있습니까?

모델 같은있다 : 결국

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

    def __unicode__(self): 
     return self.name 

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

    def __unicode__(self): 
     return self.name 

class Membership(models.Model): 
    person = models.ForeignKey(Person) 
    group = models.ForeignKey(Group) 
    date_joined = models.DateField() 
    invite_reason = models.CharField(max_length=64) 

, 그것은 그러한 예이다 : 사람 모델 인식 방법

# Find all the members of the Beatles that joined after 1 Jan 1961 
>>> Person.objects.filter(
...  group__name='The Beatles', 
...  membership__date_joined__gt=date(1961,1,1)) 
[<Person: Ringo Starr] 

내 질문은 그룹 및 구성원 속성은 정의되어 있지 않으므로 그것은 단지 많은 사람들의 마술인가? 아니면 장고에서 보편적 인 것입니까?

내가 같은 쿼리를 달성한다면, 나는 다음과 같은 생각 코드 (장고의 ORM의 관점에서가 아니라 비즈니스 하나에서) 더 자연스러운 :

Membership.objects.filter(group__name='The Beatles', date_joined__gt=date(1961,1,1))).select_related('person') 

편집 내가 다시 문서를 읽고 할 그러한 거꾸로 발견하는 것은 보편적이다. 단락 https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships에는 다음과 같이 표시됩니다.

역방향으로도 작동합니다. "역"관계를 참조하려면 모델의 소문자 이름 만 사용하십시오.

이전에이 역방향 쿼리를 사용한 적이 없습니다. 그래서 처음으로 그것을 보았을 때, 그것은 내 두뇌를 두드렸다. 죄송합니다.이 스레드는 어리 석다는 것이 밝혀졌습니다. 그러나 그 단락에서 매우 (얇은) ​​줄을 건너 뛰는 사람들에게 도움이되기를 바랍니다.

답변

2

ManyToMany 필드의 마법이 아닙니다. 그것의 보편적 인 하나의 장고 ORM 외래 키 (ManyToMany 포함) 관계.

예, 당신은

class Musician(models.Model): 
    name = models.CharField(max_length=128) 
    band = models.ForeignKey("Band") 

class Band(models.Model): 
    name = models.CharField(max_length=128) 
    genre = models.CharField(max_length=50) 

당신은 쿼리가 장고 디버그 도구 모음 또는 함께 장고 쉘에서 볼 수 Musician.objects.filter(band__name='The Beatles') 같은 것을 할 수있는 경우 :

from django.db import connection 
connection.queries 

할 것 복잡한 JOIN 문과 일치합니다. 당신이 ORM이로를 Band.objects.filter(musician__name = 'Ringo Starr') 번역 할 않은 경우 :

SELECT "appname_musician"."id", "appname_musician"."name", "appname_musician"."band_id" 
    FROM "appname_musician" 
    INNER JOIN "appname_band" ON ("appname_musician"."band_id" = "appname_band"."id") 
    WHERE "appname_band"."name" = "The Beatles"; 

편집이 :

SELECT "appname_band"."id", "appname_band"."name", "appname_band"."genre" 
    FROM "appname_band" 
    INNER JOIN "appname_musician" ON ("appname_musician"."band_id" = "appname_band"."id") 
    WHERE "appname_musician"."name" = "Ringo Starr"; 

ORM이 관계를 알고 수있는 ORM에 의해 구성된 SQL 쿼리는 같을 것 ORM 쿼리를 적절한 SQL로 변환하십시오. 밴드가 뮤지션 오브젝트를 가지고 있지 않다는 사실은 중요하지 않습니다. 장고에게 명확한 요청을 할 수있었습니다. "Ringo Starr"이라는 이름의 밴드와 연결된 뮤지션이있는 모든 밴드 오브젝트가 필요합니다.

개체 캡슐화 (예 : 밴드에 뮤지션이 없는데,이를 기반으로 필터링 할 수있는 방법)에 대해 생각할 필요가 있습니다.필터 요청이 명확하고 모호하지 않기 때문에 흑 마술이 아니며 Band 객체의 멤버가 아닌 인수를 취합니다. 에 의해 필터링하도록 명령합니다. 예를 들어, 오브젝트가없는 경우에도 Band.objects(name__icontains = "The")을 수행 할 수 있습니다. ORM은 요청을 SQL로 변환하는데, 이는 신속하게 실행하기 쉽습니다.


EDIT2 : 귀하의 최종 예 : 사용 (

class Musician(models.Model): 
    name = models.CharField(max_length=128) 
    initial_band = models.ForeignKey("Band", related_name = 'initial_band_members') 
    final_band = models.ForeignKey("Band", related_name = 'final_band_members') 

class Band(models.Model): 
    name = models.CharField(max_length=128) 
    genre = models.CharField(max_length=50) 

try: ## create some objects 
    cream,_ = Band.objects.get_or_create(name="Cream", genre="Classic Rock") 
    derek, _ = Band.objects.get_or_create(name="Derek and the Dominos", genre="Classic Rock") 
    beatles, _ = Band.objects.get_or_create(name="The Beatles", genre="Classic Rock") 
    wings, _ = Band.objects.get_or_create(name="Wings", genre="Classic Rock") 
    Musician.objects.get_or_create(name="Eric Clapton", initial_band=cream, final_band=derek) 
    Musician.objects.get_or_create(name="Paul McCartney", initial_band=beatles, final_band=wings) 
    Musician.objects.get_or_create(name="John Lennon", initial_band=beatles, final_band=beatles) 

except: 
    pass 

그런 다음 Band.objects.filter(musician__name='Paul McCartney') 같은 쿼리 (FieldError)를 작동하지 않습니다,하지만 쿼리와 같은 Band.objects.filter(initial_band_members__name='Paul McCartney')는 비틀즈는 다음과 같은 SQL 발견 다시 줄 것이다 sqlite는 db로, 명령은 DB 백엔드에 종속됩니다.)

SELECT "testing_band"."id", "testing_band"."name", "testing_band"."genre" 
    FROM "testing_band" 
    INNER JOIN "testing_musician" ON ("testing_band"."id" = "testing_musician"."final_band_id") 
    WHERE "testing_musician"."name" = Paul McCartney ' 
+0

밴드는 뮤지션 모델에 정의 된 외래 키이므로 예제를 완전히 이해할 수 있습니다. 하지만 내 질문에, Person 모델은 person 속성이 정의되어 있지 않습니다. 내 질문에 답하기 위해 Band.objects.filter (musician__name = 'Ringo Starr')와 같은 반대의 작업을 수행하는 것이 가능한지 알려주십시오. –

+0

그것은 동일한 필수 메커니즘입니다. django ORM은 장고 쿼리를 SQL로 변환합니다. 나는 예제로 편집 할 것이다. –

+0

설명해 주셔서 감사합니다. 나는이 문서를 다시 읽고 역방향 질의가 가능하다는 것을 깨달았다. 그러나 그것은 한 줄의 것입니다. 그래서 나는 내 눈이 그것을 건너 뛴 것 같아. –

1

아마 을 찾으십시오. 일반적으로 조인이 사용됩니다.

+0

이 기사 c 내 질문에 대답하지 마라. 내 질문에, Person 모델은 그룹 또는 구성원 속성을 인식하지 못합니다. 나는 django가 group_set과 membership_set managers를 추가 할 것이라는 것을 알고있다. 그러나 그룹 및 회원 속성? django doc은 그 가능성을 언급하지 않습니다. –

관련 문제