0

我想在 Django 中编写一个非常基本的标记应用程序,它几乎与文档中的通用外键示例相同(django-tagging 和 django-taggit 对我来说太过分了)。

挑战在于在标签详细信息模板中显示特定标签的所有项目,无论其内容类型如何。

我的猜测是制作一个带有名称和 slug 的标签,然后是带有 ctype/object_id/content_object 的 TaggedItem。博客文章通过 Tag 获得多对多,以及保存新 TaggedItem 的信号。也许 TaggedItem 应该得到一个蛞蝓?也许 Post 应该得到一个通用关系而不是多对多?我的查询猜测tags/views.pycontext['tagged_items']. 这就是我现在卡住的地方。

# blog/models.py:

from django.db import models
from django.core.urlresolvers import reverse
from django.utils import timezone

class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField()
    body = models.TextField()
    tags = models.ManyToManyField('tags.Tag', blank=True)
    published = models.DateTimeField(default=timezone.now)

    class Meta:
        ordering = ['-published']

    def __unicode__(self):
        return u'%s' % self.title

    def get_absolute_url(self):
        return reverse('blog.views.post_detail', args=[str(self.slug)])

# tags/models.py:

from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db.models.signals import post_save

from blog.models import Post


class Tag(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField()

    def __unicode__(self):
        return u'%s' % self.title

    def get_absolute_url(self):
        return reverse('tags.views.tag_detail', args=[str(self.slug)])


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


def create_tagged_item(sender, **kwargs):
    if 'created' in kwargs:
        if kwargs['created']:
            instance = kwargs['instance']
            if instance.tags.all:
                content_type = ContentType.objects.get_for_model(instance)
                object_id = instance.id
                tagged_item = TaggedItem.objects.create(content_type=content_type, object_id=object_id)


post_save.connect(create_tagged_item, sender=Post)

# tags/views.py:

from django.views.generic import ListView, DetailView
from django.contrib.contenttypes.models import ContentType

from .models import Tag
from .models import TaggedItem


class TagListView(ListView):
    model = Tag


class TagDetailView(DetailView):
    model = Tag

    def get_context_data(self, **kwargs):
        context = super(TagDetailView, self).get_context_data(**kwargs)
        context['tagged_items'] = TaggedItem.objects.filter(content_object__tags__in=self.object.slug) # ????
        return context
4

2 回答 2

0

Tag 和 TaggedItem 之间没有任何关系,这使事情变得困难。

在我看来,M2M 应该介于这两个模型之间,而不是在 Post 上。关键是任何东西都可以“成为”标记项目,因此是通用关系,并且该项目可以有多个标签。有了它,您可以执行以下操作:

tag = Tab.objects.get(slug=my_slug)
tagged_items = TaggedItem.objects.filter(tags=tag)
content_objects = [item.content_object for item in tagged_items]

但实际上,如果您为了简单起见,我不知道您为什么不完全使用文档中的代码,而根本没有单独的 Tag 模型。您最终会得到许多具有相同标签 slug/name 的 TaggedItem,但这没关系:您仍然可以这样做

tagged_items = TaggedItem.objects.filter(slug=my_slug)

并像以前一样获取 content_objects。

于 2013-08-15T20:39:16.453 回答
0

我最终采用了 Timo Zimmermann 的方法:遍历通用条目项目上的可能标签。http://www.screamingatmyscreen.com/2012/6/django-and-generic-relations/管理员友好,不需要TaggedItem

class TagDetailView(DetailView):
    model = Tag

    def get_context_data(self, **kwargs):
        context = super(TagDetailView, self).get_context_data(**kwargs)

        item_list = []
        for item in ActivityItem.objects.all():
            if self.object in item.tags:
                item_list.append(item)

        context['item_list'] = item_list
        return context

感谢@DanielRoseman 和@Ben 参与进来。

于 2013-08-19T16:50:09.703 回答