2

GenericForeignKey を 1 つ含む「エントリ」モデルがあります。

class Entry(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

また、「メモ」や「ファイル」などの異なるコンテンツ モデル:

class Note(models.Model):
    title = models.CharField(max_length=255)
    text = models.TextField()

class File(models.Model):
    title = models.CharField(max_length=255)
    file_field = models.FileField('File', upload_to='files')
    description = models.TextField(blank=True)

それらが保存されている場合、新しい「エントリ」が自動的に作成されるため、次の方法ですべてのコンテンツを一覧表示できます。

Entry.objects.all()

現在、すべてのエントリとその詳細を任意の順序 (日付順など) でリストするビューとテンプレートを作成する方法を探しています。これはどのように行うことができますか?

部分的なテンプレートを特定のモデルに関連付けることはできますか? テンプレートは、リスト内の特定のインスタンスを表示する方法をどのように知っていますか?

単純化されていない models.py 全体は次のようになります。

    from django.db.models.signals import post_save, pre_delete

import datetime

class Entry(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    def title(self):
        return self.content_object.title

    def __unicode__(self):
        return self.title()

class DateModel(models.Model):
    """ A model for basic date awareness """
    modified_date = models.DateTimeField(blank=True, null=True)
    created_date = models.DateTimeField(blank=True)

    class Meta:
        abstract = True
        ordering = ['-created_date']

    def save(self, *args, **kwargs):
        if not self.pk:
            self.created_date = datetime.datetime.now()
        else:
                self.modified_date = datetime.datetime.now()
        return super(DateModel, self).save(*args, **kwargs)

class Tag(DateModel):
    name = models.CharField(max_length=51, unique=True)

    def __unicode__(self):
        return self.name


class Notebook(models.Model):
    name = models.CharField(max_length=50, unique=True)
    description = models.TextField(blank=True)

    def __unicode__(self):
        return self.name

class EntryModel(DateModel):
    """All Entry models are inherited from this abstract class"""
    title = models.CharField(max_length=255)
    notebook = models.ForeignKey(Notebook, blank=True, null=True)
    tags = models.ManyToManyField(Tag, blank=True, null=True)

    class Meta:
        abstract = True

    def __unicode__(self):
        return self.title

    ######## Begin: Entry Classes ########

class Memo(EntryModel):
    text = models.TextField()

    def save(self, *args, **kwargs):
        if self.title == '-' or self.title == '':
            if len(self.text) > 20:
                self.title = self.text[:17]+'...'
            else:
                self.title = self.text
        return super(EntryModel, self).save(*args, **kwargs)

class File(EntryModel):
    file_field = models.FileField('File', upload_to='files')
    description = models.TextField(blank=True)

    ######## End: Entry Classes ########

def create_entry(sender, **kwargs):
    """Handler for post_save signal to create new Entry"""
    if 'created' in kwargs:
        if kwargs['created']:
            instance = kwargs['instance']
            ctype = ContentType.objects.get_for_model(instance)
            entry = Entry.objects.get_or_create(
                content_type=ctype,
                object_id=instance.id)

def delete_entry(sender, **kwargs):
    """Handler for pre_delete signal to delete related Entry"""
    instance = kwargs['instance']
    ctype = ContentType.objects.get_for_model(instance)
    entry = Entry.objects.get(
        content_type=ctype,
        object_id=instance.id)
    entry.delete()

    # Connect handler to post_save signal
entry_classes = EntryModel.__subclasses__()
for cls in entry_classes:
    post_save.connect(create_entry, sender=cls)
    pre_delete.connect(delete_entry, sender=cls)
4

1 に答える 1

0

コメントで述べたように、エントリはメモまたはファイルのいずれかです。したがって、IMO モデルの継承は、ユース ケースにより適しています。models.py は次のようになります。

django.contrib.contenttypes.models からの models.py インポート ContentType

class Entry(models.Model):
    title = models.CharField(max_length=255)
    real_type = models.ForeignKey(ContentType, editable=False)
    created = models.DateTimeField(auto_now_add=True, editable=False, verbose_name='creation date')

    def save(self):
        if not self.id:
            self.real_type = self._get_real_type()
            self.created = datetime.today()
        self.modified = datetime.today()
        super(ListType, self).save()

    def _get_real_type(self):
        return ContentType.objects.get_for_model(type(self))

class Note(Entry):
    text = models.TextField()

class File(Entry):
    file_field = models.FileField('File', upload_to='files')
    description = models.TextField(blank=True)

これは、ビューで次のことができることを意味します。

Entry.objects.all().order_by('created')
#get the corresponding child
note = Note.objects.get(entry_ptr_id=parent.pk)
print note.text

継承に関する詳細については、私の別の投稿を参照してください。

エントリの「実際のタイプ」をモデルに保存するために、real_type フィールドを追加しました。このアプローチは、この投稿で提案されています。

コンテンツ タイプをモデルに保存するreal_typeと、対象がメモかファイルかを事前に知らなくても、すべてのエントリとその詳細を照会できます。

 entries = Entry.objects.all().order_by('created')
 for entry in entries:
     #get the correct child model
     childModel = entry.real_type.model_class()
     #get the child
     child = childModel.objects.get(pk=entry.pk)

     if entry.real_type.model == "Note":
         #it s a note object
         print entry.text

ドキュメントからのメモ:model_class() returns the Python model class for this type of content.

于 2012-09-26T17:16:22.437 に答える