2012-10-09 24 views
8

Tengo una página con muchos objetos con diferentes tipos de contenido. Necesito tener la capacidad de calificar estos objetos. Aquí es una clase para la que:Django obtener ContentType en una plantilla

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'),) 

Y mi plantilla debe verse como:

... 
{% 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 %} 
... 

puedo hacer etiqueta de plantilla para conseguirlo, o conseguir un nombre de clase, utilizando por ejemplo este fragmento: http://djangosnippets.org/snippets/294/ I puede reescribir este snuppet para obtener el content_type_id para el objeto, pero me temo un poco acerca de la gran cantidad de búsquedas CT en DB.

¿Pero hay algún método integrado para obtener el CT del objeto en una plantilla?

El código de la vista:

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

¿Puedes poner el código de tu vista? –

+1

Solo para información: No debe agregar tantos espacios después de sus variables. No es PEP8 (http://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements) – Thomas

Respuesta

10

Para construir sobre la respuesta @Colleen 's, terminé usando un filtro de plantilla de este modo:

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) 

y lo utilizó en una plantilla así:

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

para mayor discusión y bifurcación, [consulte este fragmento] (https: // djangosnippets.org/snippets/3015/) – tutuDajuju

+0

Esta sintaxis '' {% con instancia | content_type as ctype%} '', ¿está documentada y es compatible? ¿'' {% With a = b | c%} '' también funciona? ¿Qué pasa con '' {% con a = b | c d = e | f%} ''? No puedo encontrarlo en la documentación. –

+0

'con' es una etiqueta de plantilla incorporada (a diferencia del filtro personalizado anterior), [aquí está en los documentos oficiales de Django] (https://docs.djangoproject.com/en/1.6/ref/templates/builtins/# con) – tutuDajuju

2

Yo también tenía una situación en la que necesitaba el tipo de contenido en la plantilla y la única manera que encontré que pude conseguir fue a través de una etiqueta de plantilla personalizada.

En su situación, sin embargo, ya que está almacenando content_type explícitamente como una clave externa, no me preocuparía. En el peor de los casos, puede usar prefetch_related() cuando obtiene sus objetos de puntuación en la vista. No sé si Django es lo suficientemente inteligente como para detenerse en el campo si solicita una clave extranjera. Es lo único.

1

Yo prefiero hacer esto con assignment tags (nuevo en Django 1.4):

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

y se utiliza como

{% content_type object as object_ct %} 
Cuestiones relacionadas