2013-03-25 32 views
2

我有點難以理解這一點。我有兩個自定義用戶模型(例如:Buyer,Seller),它擴展了一個包含所有常用字段(包括我們需要用來過濾東西的email)的單個自定義用戶模型(CustomUser),並且是abstract模型。在Django中使用GenericForeignKey進行復雜的過濾

現在,我們正在使用第三方電子郵件服務來收發來自我們應用程序的電子郵件。第三方服務通知我們一個事件。比如說,如果電子郵件被退回或失敗,他們會向我們發送一個POST請求,並且在對請求進行身份驗證後,我們會更新我們的記錄並記錄哪些電子郵件失敗。

我們有一個額外的電子郵件模型(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,可以綁定到任何其它模型(在本例中買方或賣方)。這是我們將更新記錄的模型,如果消息在退回事件中發生變化等。我期望使用第三方服務提供的電子郵件地址過濾掉收件人。所以流量基本上是這樣的。

- >使用給定的電子郵件地址過濾出收件人(收件人可以是買方或賣方) - >使用上述過濾器SentMessage根據事件類型彈跳或失敗。

我被困在這裏的第一點。如何過濾Buyer模型或Seller模型中存在的對象。我甚至不能做到以下爲CustomUser類是一個抽象類,從中既BuyerSeller繼承:

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

什麼會發現,從最好的辦法(過濾器)出content_typeobject_idrecipient給的電子郵件地址

+0

這是你需要去的地方https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/首先你得到content_type的類,然後使用object_id得到對象 – n3storm 2013-03-25 08:13:32

回答

1

這是你需要去https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/

首先你得到的類包括content_type,然後使用OBJECT_ID

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

這不會工作。正如我在問題中指出的那樣,CustomUser是一個抽象類,你不能直接從中過濾對象。 – Amyth 2013-03-25 08:21:54

+0

對不起,忘記寫下來:給你的抽象類添加一個代理。 https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-model-managers。另外,恕我直言,選擇這種情況下的抽象模型是錯誤的。 – n3storm 2013-03-25 09:14:39

0

獲取對象我會傾向於n3storm同意,一個抽象的模型可能不適合這種情況,但我會假設你有你使用它的理由。

在這種情況下,也許是GenericRelation在具體的車型會做的伎倆,因爲GenericRelation充當一個GenericForeignKey一個「反向關係」。 (https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericRelation

E.g.類似可能的工作:

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引用其他模型相比BuyerSeller。這可以通過在content_type FK中使用limit_choices_to來避免,儘管您必須確保調用SentMessage模型實例的full_clean方法來應用驗證(https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects)。 Django Admin正確使用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

相關問題