51

メッセージの送信者と受信者が一般的なエンティティになるメッセージング システムを作成しようとしています。これは、参照するオブジェクト (GenericForeignKey) しかない送信者にとっては問題ないようですが、受信者 (GenericManyToManyKey ??) に対してこれを行う方法がわかりません。

以下は簡単な例です。PersonClient と CompanyClient は Client から属性を継承しますが、固有の詳細があります。最後の行はこだわりポイントです。メッセージ受信者が CompanyClients と 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)
4

3 に答える 3

63

メッセージと受信者の間のジャンクション テーブルを手動で作成することにより、一般的な関係を使用してこれを実装できます。

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)

上記のモデルを次のように使用します。

>>> 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

ご覧のとおり、これははるかに冗長な (複雑な?) ソリューションです。私はおそらくそれを単純に保ち、以下の Prariedogg のソリューションを使用します。

于 2009-06-02T00:10:47.300 に答える
10

これを行うための絶対的な最善の方法は、django-gm2m というライブラリを使用することです。

pip install django-gm2m

次に、モデルがある場合

>>> from django.db import models
>>>
>>> class Video(models.Model):
>>>       class Meta:
>>>           abstract = True
>>>
>>> class Movie(Video):
>>>     pass
>>>
>>> class Documentary(Video):
>>>     pass

そして、ユーザー

>>> from gm2m import GM2MField
>>>
>>> class User(models.Model):
>>>     preferred_videos = GM2MField()

我々はできる

>>> user = User.objects.create()
>>> movie = Movie.objects.create()
>>> documentary = Documentary.objects.create()
>>>
>>> user.preferred_videos.add(movie)
>>> user.preferred_videos.add(documentary)

甘いでしょ?

詳細については、こちらをご覧ください:

http://django-gm2m.readthedocs.org/en/stable/quick_start.html

于 2015-10-07T10:13:16.453 に答える
7

この問題を回避するには、スキーマを単純化して、Client2 つの別個のモデルを用意するのではなく、クライアントのタイプを示すフラグ付きの単一のテーブルを含めます。

from django.db import models
from django.utils.translation import ugettext_lazy as _

class Client(models.Model):
    PERSON, CORPORATION = range(2)
    CLIENT_TYPES = (
                    (PERSON, _('Person')),
                    (CORPORATION, _('Corporation')),
                   )
    type = models.PositiveIntegerField(choices=CLIENT_TYPES, default=PERSON)
    city = models.CharField(max_length=16)
    first_name = models.CharField(max_length=16, blank=True, null=True)
    last_name = models.CharField(max_length=16, blank=True, null=True)
    corporate_name = models.CharField(max_length=16, blank=True, null=True)
    tax_no = models.PositiveIntegerField(blank=True, null=True)

    def save(self, *args, **kwargs):
        """
        Does some validation ensuring that the person specific fields are
        filled in when self.type == self.PERSON, and corporation specific
        fields are filled in when self.type == self.CORPORATION ...

        """
        # conditional save logic goes here
        super(Client, self).save(*args, **kwargs)

このようにすれば、一般的な外部キーをいじる必要がまったくないかもしれません。追加の利便性として、 、 などの Client モデルのカスタム マネージャーを記述して、Client.corporate.all()必要なClient.person.all()クライアントの種類のみを含む事前にフィルター処理されたクエリセットを返すこともできます。

これは、問題を解決する最善の方法ではない場合もあります。ひとつの可能性として投げ出してるだけ。2 つの類似したモデルを一緒に粉砕し、上書き保存を使用してデータの整合性を確保することについて、従来の知恵があるかどうかはわかりません。問題が発生する可能性があるようです...コミュニティにこれについて教えてもらいます。

于 2009-06-01T02:02:47.063 に答える