2012-10-09 74 views
8

我有一個包含許多不同內容類型的對象的頁面。我需要有能力評價這個對象。下面是它的一類:Django在模板中獲取ContentType

class Score(models.Model): 
    user   = models.ForeignKey(User) 

    content_type = models.ForeignKey(ContentType) 
    object_id  = models.PositiveIntegerField() 
    for_object  = generic.GenericForeignKey('content_type', 'object_id') 

    like   = models.BooleanField(default=True) 
    created_at  = models.DateTimeField(auto_now_add=True, blank=True, null=True) 

    comment   = models.CharField(max_length=255, blank=True, null=True) 

    objects = ChainerManager(ScoreQuerySet) 

    def __unicode__(self): 
     return u'Score for (%s, #%s) from user %s at %s' %\ 
      (self.content_type, self.object_id, self.user.get_full_name(), self.created_at) 

    class Meta: 
     unique_together = (('user', 'content_type', 'object_id'),) 

而且我的模板應該是這樣的:

... 
{% for random_object in random_object_queryset %} 
<a href={% url like_object random_object.<content_type> random_object.id %}>{{ random_object.name }}</a> 
<a href={% url dislike_object random_object.<content_type> random_object.id %}>{{ random_object.name }}</a> 
{% endfor %} 
... 

我可以做模板標籤得到它,或者得到一個類名,即使用這段代碼:http://djangosnippets.org/snippets/294/ 我可以重寫這個snuppet來獲取對象的content_type_id,但是我擔心在DB中大量的CT查找。

但是有沒有一種嵌入式的方法來獲取對象的CT模板?

視圖代碼:

def rate_object(request, classname, object_id, like=True): 
    user = request.user 
    Klass = ContentType.objects.get(model=classname).model_class() 
    obj = get_object_or_404(Klass, user=user, pk=object_id) 

    try: 
     score = Score.objects.for_object(user, obj) 
     score.like = like 
     score.save() 
    except Score.DoesNotExist: 
     score = Score.objects.like(user, obj) if like else Score.objects.dislike(user, obj) 

    return HttpResponse(obj) 
+0

你可以把你的視圖代碼? –

+1

僅供參考:您不應在變量之後添加太多空格。這不是PEP8(http://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements) – Thomas

回答

10

要建立在@Colleen的答案,我結束了使用模板過濾器像這樣:

from django import template 
from django.contrib.contenttypes.models import ContentType 

register = template.Library() 

@register.filter 
def content_type(obj): 
    if not obj: 
     return False 
    return ContentType.objects.get_for_model(obj) 

,並用它在模板中像這樣:

{% load helpers %} 
{% with instance|content_type as ctype %} 
    <input type="hidden" name="content_type" value="{{ ctype.pk }}"> 
{% endwith %} 
+0

進一步討論和分叉,[見這個片段](https:// djangosnippets.org/snippets/3015/) – tutuDajuju

+0

這個''{%with instance | content_type as ctype%}'語法,是否記錄並支持? 「{%with a = b | c%}''也可以工作嗎?怎麼樣''{%with a = b | c d = e | f%}''?我無法在文檔中找到它。 –

+0

'with'是一個內置的模板標籤(與上面的自定義過濾器相反),[這裏是在Django官方文檔中](https://docs.djangoproject.com/en/1.6/ref/templates/builtins /#與) – tutuDajuju

2

我也有地方,我需要的模板,我發現我能得到它是通過自定義的模板標籤的唯一辦法內容類型的情況。

但是,在你的情況下,因爲你將content_type顯式地存儲爲外鍵,所以我不擔心它。最糟糕的情況下,當您在視圖中獲得樂譜對象時,您可以使用prefetch_related()。我不知道Django是否足夠聰明,如果你要求一個foreignkey.id是唯一的話,那麼他可以在現場停下來。

1

我更喜歡這樣做與assignment tags(新在Django 1.4):

@register.assignment_tag 
def content_type(obj): 
    if not obj: 
     return False 
    return ContentType.objects.get_for_model(obj) 

並用作

{% content_type object as object_ct %}