2013-03-25 2 views
2

나는이 것을 고치기가 힘듭니다. 모든 공통 필드 (예 : email을 사용하여 항목을 필터링해야 함)를 보유하는 단일 사용자 정의 사용자 모델 (CustomUser)을 확장하고 abstract 모델 인 두 개의 사용자 정의 사용자 모델 (예 : Buyer, Seller)이 있습니다.django에서 GenericForeignKey로 복잡한 필터링

이제 타사 이메일 서비스를 사용하여 Google 애플리케이션과 이메일 메시지를주고받습니다. 제 3 자 서비스는 이벤트에 관해 우리에게 알려줍니다. 예를 들어 이메일이 반송되거나 실패하면 callback url에 POST 요청을 보내고 요청을 인증 한 후 Google에서 기록을 업데이트하고 실패한 이메일을 기록합니다.

전송 된 메시지를 저장하는 추가 전자 메일 모델 (SentMessage)이 있습니다. 이 모델은 이와 유사합니다.

class SentMessage(models.Model): 
    subject = models.CharField(max_length=100) 
    body = models.TextField() 
    sender = models.ForeignKey(models.InternalUser) 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    recipient = generic.GenericForeignKey('content_type', 'object_id') 
    bounced = models.BooleanField(default=False) 

당신이 볼 수 있듯이, 위의 모델에서 recipient 필드는 GenericForeignKey이며, (우리의 경우 구매자 또는 판매자에) 다른 모델에 바인딩 할 수 있습니다. 이 모델은 바운스 이벤트 등에서 메일이 수신되면 레코드를 업데이트 할 모델입니다. 제 3 자 서비스에서 제공 한 이메일 주소로 수신자를 필터링하려고합니다. 그래서 기본적으로 흐름은 비슷한 것입니다.

-> 주어진 이메일 주소를 사용하여 수신자를 필터링하십시오 (수신자가 구매자 또는 판매자 일 수 있음) -> 위의 내용을 사용하여 이벤트 유형에 따라 반송되거나 실패한 필터 SentMessage .

나는 여기서 첫 번째 지점에 머물러있다. Buyer 모델 또는 Seller 모델에있는 개체를 필터링하려면 어떻게해야합니까? CustomUser 클래스는 추상 클래스는, 그대로 난 다음 작업을 수행 할 수없는 두 BuyerSeller 상속 :

recipient = models.CustomUser.objects.get(email=bounced_email) 

A로부터 찾을 수있는 가장 좋은 방법 (필터) 밖으로 content_type, object_id, recipient이 될 것입니다 무엇 주어진 이메일 주소?

+0

여기 가야 할 곳은 https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/입니다. 먼저 content_type 클래스를 가져온 다음 object_id – n3storm

답변

1

당신은 내가 n3storm에 동의하는 경향이

recipient = models.CustomUser.objects.get(email='[email protected]') 
messages = SentMessage.objects.filter(content_object=recipient, email=bounced_email) 
+0

을 사용하여 개체를 가져옵니다. 작업. 'CustomUser'라는 질문에서 지적했듯이 추상 클래스이므로 객체를 직접 필터링 할 수 없습니다. – Amyth

+0

죄송합니다. 작성을 잊어 버리십시오 : 추상 클래스에 프록시를 추가하십시오. https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-model-managers. 또한 IMHO는이 경우 추상적 모델을 선택하는 것은 잘못된 것입니다. – n3storm

0

를 OBJECT_ID 사용하여 객체를 얻을 다음 https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/

먼저 가서 당신이 콘텐츠 _의 클래스를 얻을 필요가있는 곳은 추상 모델은 수도 이 사건에 이상적은 아니지만, 당신이 그 이유를 알고 있다고 생각합니다.

GenericRelationGenericForeignKey에 대해 '역방향 관계'로 작동하므로 콘크리트 모델의 GenericRelation이이 트릭을 수행합니다. (https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericRelation)

예. 힘 작업과 같은 : 검증에 대한

class CustomUser(models.Model): 
    # ... your common fields 

    class Meta: 
     abstract = True 

class Buyer(CustomUser): 
    # ... buyer-specific fields 
    sent_messages = GenericRelation(SentMessage) 

class Seller(CustomUser): 
    # ... seller-specific fields 
    sent_messages = GenericRelation(SentMessage) 


recipient_list = [x for x in Buyer.objects.filter(sent_messages=bounced_email)] + 
       [x for x in Seller.objects.filter(sent_messages=bounced_email)] 
# The above list can contain at most one element since a SentMessage will reference at most one object. 

일부 발언 : 당신이 SentMessage.content_type FK에 대한 몇 가지 검증을 넣어하지 않는 한, 그것은 GFK가 Buyer 또는 Seller 아닌 다른 모델을 참조하는 불가능 아니다.content_type FK에서 limit_choices_to을 사용하여 방지 할 수 있지만 full_clean 메서드 SentMessage 모델 인스턴스를 호출하여 유효성 검사 (https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects)를 적용해야합니다. Django 관리자는 limit_choices_to을 사용하여 유효하지 않은 FK 값을 입력하지 못하도록합니다.

또한 기본적으로 GFK는 참조하고있는 object_id의 존재를 강요하지 않는다고 생각합니다 (적어도 1.4 이상 사용하고 있습니다). 즉 위의 예에서 recipient_list이 비어있는 경우가 발생할 수 있습니다.

경고 : 모델에 GenericRelation을 추가하면 해당 모델의 인스턴스를 삭제해도 GFK 링크 항목이 연쇄 적으로 삭제됩니다.이 경우 Buyer을 삭제하면 Buyer과 관련된 SentMessage이 모두 삭제된다는 의미입니다. 이 기능/제한을 해결하는 방법에 대한 자세한 내용은 https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericRelation을 참조하십시오.

관련 문제