How do I apply a filter in a custom template tag?

21 views
Skip to first unread message

Josh

unread,
Aug 13, 2011, 12:49:31 PM8/13/11
to django...@googlegroups.com
I'm trying to retrieve a m2m relation from a blog entry. It should give a list of entries with the same categories. Below works when I work in the shell.

from content.models import Entry
qs = Entry.objects.all()
obj = qs[0]
related = Entry.objects.filter(categories=obj.categories.all())

The obj simulates a single Entry in a template for use in the shell.

I'm trying to put this in a custom template tag, so a list of related entries can be shown with a blog entry. I cooked up the following:

            {% load content_tags %}
                {% get_related_entries content.entry from object.categories.all as related_entries %}
                    {% for item in related_entries %}
                            <p><a href="{{ item.get_absolute_url }}">{{ item.title }}</a>
                    {% endfor %}

This isn't working though. I'm not sure how to do this, even after (re)reading Django-books and documentation. When I don't apply a filter and the following in the Node render() works:

context[self.varname] = self.model.objects.all()

Obviously I get a list of all entries, without any filter. I'm pretty sure it has to do with the object.categories.all (which is a list of all categories) in my template tag and the use of it in the parser/Node. How can I achieve this? 

PS:
I didn't include any of my (now many) variants of code I tried on purpose. I suspect I'm following an entirely wrong approach and don't want to focus attention at wrong code. 

Doug Ballance

unread,
Aug 13, 2011, 4:10:00 PM8/13/11
to Django users
I'd like to see you model structure, but based on what I think it is:

class Entry(model.Model):
categories=models.ManyToManyField(Category)

class Content(models.Model):
entry=models.ForeignKey(Entry)

You have a Content Instance
You want to see other entries belonging to one or more of the
categories for that Content instances Entry instance

You could do a custom template tag like yours:

{% get_related_entries content_instance.entry as related_entries %}

That tag would do something like the following :

#fetching primary key only since we don't need the whole thing
category_ids=content_instance.entry.categories.values("pk")
context['related_entries']=Entry.objects.filter(pk__in=category_ids)

That would work, but my choice would probably be to add a method to
your Entry class.

class Entry(models.Model):
categories=models.ManyToManyField(Category)

def related_entries(self,**filters):
return
Entry.objects.filter(pk__in=self.categories.filter(**filters).values("pk"))

That way you don't need a tag at all. Just do:

{% for related_entry in content.entry.related_entries %}
...
{% endfor %}

Josh

unread,
Aug 14, 2011, 6:40:37 AM8/14/11
to django...@googlegroups.com
Thanks, I've added a function to the Enty models. It doesn't in some cases I get good returns now. But not always.

Content is the name of the app. There is no PK-relation on the Category class, but only the below on the Entry class.

class Entry(models.Model):
    categories = models.ManyToManyField(Category, blank=True, null=True, default = None)

    def related_entries(self):
        related = Entry._default_manager.get(categories=self.categories.all())
        return related

            {% for related_entry in object.related_entries %}
                <p><a href="{{ related_entry.get_absolute_url }}">{{ related_entry.title }}</a></p>
            {% endfor %}


The related_entries work when all categories match. If there is a difference (e.g. an Entry has multiple categories) it should return none. Instead I get an error statement, which is probably because for each assigned category to the entry a row is returned. 

Caught DatabaseError while rendering: more than one row returned by a subquery used as an expression
Reply all
Reply to author
Forward
0 new messages