2

我有一个“Entry”模型,包含一个 GenericForeignKey:

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

以及“Note”和“File”等不同的内容模型:

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内容类型后,您可以查询所有条目及其详细信息,而无需预先知道您是在处理 Notes 还是 Files。

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