2013-03-25 78 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

相关问题