通用的多对多关系 [英] Generic many-to-many relationships

查看:158
本文介绍了通用的多对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个邮件系统,邮件的发件人和收件人可以是通用实体。这对发件人来说似乎很好,只有对象可以引用(GenericForeignKey),但是我无法弄清楚收件人如何处理这个问题(GenericManyToManyKey?)



下面是一个简化的例子。 PersonClient和CompanyClient从Client继承属性,但具有自己的具体细节。最后一行是粘贴点。您如何允许邮件收件人成为一组CompanyClients和PersonClients

 类客户端(models.Model):
city = models.CharField(max_length = 16)

class Meta:
abstract = True

class PersonClient(Client):
first_name = models。 CharField(max_length = 16)
last_name = models.CharField(max_length = 16)
gender = models.CharField(max_length = 1)

class CompanyClient(Client):
name = models.CharField(max_length = 32)
tax_no = PositiveIntegerField()

类消息(models.Model):
msg_body = models.CharField(max_length = 1024 )
sender = models.ForeignKey(ContentType)
recipient = models.ManyToManyField(ContentType)


解决方案

您可以通过手动创建消息和收件人之间的连接表来实现此类通用关系:


$ b来自django.db导入模型

从django.contrib.contenttypes导入通用
从django.contrib.contenttypes.models导入ContentType

class客户端(models.Model):
city = models.CharField(max_length = 16)

#这些不是必需的,但是它们会让你做一些很酷的东西
#喜欢person.sent_messages.all()以获取所有发送的消息
#,而person.received_messages.all()到
#将所有发送到那个人。
#好的,因为received_messages.all()将返回
#一个MessageRecipient实例的查询。
sent_messages = generic.GenericRelation('Message',
content_type_field ='sender_content_type',
object_id_field ='sender_id'

received_messages = generic.GenericRelation('MessageRecipient ',
content_type_field ='recipient_content_type',
object_id_field ='recipient_id'


class Meta:
abstract = True

class PersonClient(Client):
first_name = models.CharField(max_length = 16)
last_name = models.CharField(max_length = 16)
gender = models.CharField(max_length = 1)

def __unicode __(self):
return u'%s%s'%(self.last_name,self.first_name)

class CompanyClient(Client)
name = models.CharField(max_length = 32)
tax_no = models.PositiveIntegerField()

def __unicode __(self):
return self.name

class Message(models.Model):
sender_conte nt_type = models.ForeignKey(ContentType)
sender_id = models.PositiveIntegerField()
sender = generic.GenericForeignKey('sender_content_type','sender_id')
msg_body = models.CharField(max_length = 1024 )

def __unicode __(self):
return u'%s ...'%self.msg_body [:25]

class MessageRecipient(models.Model )
message = models.ForeignKey(Message)
recipient_content_type = models.ForeignKey(ContentType)
recipient_id = models.PositiveIntegerField()
recipient = generic.GenericForeignKey('recipient_content_type' ,'recipient_id')

def __unicode __(self):
return u'%s发送到%s'%(self.message,self.recipient)

您可以使用上述模型:

 >>> person1 = PersonClient.objects.create(first_name ='Person',last_name ='One',gender ='M')
>>> person2 = PersonClient.objects.create(first_name ='Person',last_name ='Two',gender ='F')
>>> company = CompanyClient.objects.create(name ='FastCompany',tax_no ='4220')
>>> company_ct = ContentType.objects.get_for_model(CompanyClient)
>>> person_ct = ContentType.objects.get_for_model(person1)#为实例工作。

#现在我们创建一个消息:

>>> msg = Message.objects.create(sender_content_type = person_ct,sender_id = person1.pk,msg_body ='嘿,你们有没有移动我的奶酪?')

#并将其发送给coupla收件人:

>>> MessageRecipient.objects.create(message = msg,recipient_content_type = person_ct,recipient_id = person2.pk)
>>> MessageRecipient.objects.create(message = msg,recipient_content_type = company_ct,recipient_id = company.pk)
>>> MessageRecipient.objects.count()
2

如你所见,这是一个远更详细(复杂的)解决方案。我可能会保持简单,并与上面的Prariedogg解决方案一起走。


I'm trying to create a messaging system where a message's sender and recipients can be generic entities. This seems fine for the sender, where there is only object to reference (GenericForeignKey) but I can't figure out how to go about this for the recipients (GenericManyToManyKey ??)

Below is a simplified example. PersonClient and CompanyClient inherit attributes from Client but have their own specific details. The last line is the sticking point. How do you allow message recipients to be a set of CompanyClients and PersonClients

  class Client(models.Model):
      city = models.CharField(max_length=16)

      class Meta:
          abstract = True

  class PersonClient(Client):
      first_name = models.CharField(max_length=16)
      last_name = models.CharField(max_length=16)
      gender = models.CharField(max_length=1)

  class CompanyClient(Client):
      name = models.CharField(max_length=32)
      tax_no = PositiveIntegerField()

  class Message(models.Model):
      msg_body = models.CharField(max_length=1024)
      sender = models.ForeignKey(ContentType)
      recipients = models.ManyToManyField(ContentType)

解决方案

You can implement this using generic relationships by manually creating the junction table between message and recipient:

from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType

class Client(models.Model):
    city = models.CharField(max_length=16)

    # These aren't required, but they'll allow you do cool stuff
    # like "person.sent_messages.all()" to get all messages sent
    # by that person, and "person.received_messages.all()" to
    # get all messages sent to that person.
    # Well...sort of, since "received_messages.all()" will return
    # a queryset of "MessageRecipient" instances.
    sent_messages = generic.GenericRelation('Message',
        content_type_field='sender_content_type',
        object_id_field='sender_id'
    )
    received_messages = generic.GenericRelation('MessageRecipient',
        content_type_field='recipient_content_type',
        object_id_field='recipient_id'
    )

    class Meta:
        abstract = True

class PersonClient(Client):
    first_name = models.CharField(max_length=16)
    last_name = models.CharField(max_length=16)
    gender = models.CharField(max_length=1)

    def __unicode__(self):
        return u'%s %s' % (self.last_name, self.first_name)

class CompanyClient(Client):
    name = models.CharField(max_length=32)
    tax_no = models.PositiveIntegerField()

    def __unicode__(self):
        return self.name

class Message(models.Model):
    sender_content_type = models.ForeignKey(ContentType)
    sender_id = models.PositiveIntegerField()
    sender = generic.GenericForeignKey('sender_content_type', 'sender_id')
    msg_body = models.CharField(max_length=1024)

    def __unicode__(self):
        return u'%s...' % self.msg_body[:25]

class MessageRecipient(models.Model):
    message = models.ForeignKey(Message)
    recipient_content_type = models.ForeignKey(ContentType)
    recipient_id = models.PositiveIntegerField()
    recipient = generic.GenericForeignKey('recipient_content_type', 'recipient_id')

    def __unicode__(self):
        return u'%s sent to %s' % (self.message, self.recipient)

You'd use the above models like so:

>>> person1 = PersonClient.objects.create(first_name='Person', last_name='One', gender='M')
>>> person2 = PersonClient.objects.create(first_name='Person', last_name='Two', gender='F')
>>> company = CompanyClient.objects.create(name='FastCompany', tax_no='4220')
>>> company_ct = ContentType.objects.get_for_model(CompanyClient)
>>> person_ct = ContentType.objects.get_for_model(person1) # works for instances too.

# now we create a message:

>>> msg = Message.objects.create(sender_content_type=person_ct, sender_id=person1.pk, msg_body='Hey, did any of you move my cheese?')

# and send it to a coupla recipients:

>>> MessageRecipient.objects.create(message=msg, recipient_content_type=person_ct, recipient_id=person2.pk)
>>> MessageRecipient.objects.create(message=msg, recipient_content_type=company_ct, recipient_id=company.pk)
>>> MessageRecipient.objects.count()
2

As you can see, this is a far more verbose (complicated?) solution. I'd probably keep it simple and go with Prariedogg's solution above.

这篇关于通用的多对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆